user32: Rearrange ComboBox repositioning code.
[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 /* kernel32 functions */
1725 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1726
1727 static void init_procs(void)
1728 {
1729     HMODULE user32 = GetModuleHandleA("user32.dll");
1730     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1731
1732 #define GET_PROC(dll, func) \
1733     p ## func = (void*)GetProcAddress(dll, #func); \
1734     if(!p ## func) { \
1735       trace("GetProcAddress(%s) failed\n", #func); \
1736     }
1737
1738     GET_PROC(user32, GetAncestor)
1739     GET_PROC(user32, GetMenuInfo)
1740     GET_PROC(user32, NotifyWinEvent)
1741     GET_PROC(user32, SetMenuInfo)
1742     GET_PROC(user32, SetWinEventHook)
1743     GET_PROC(user32, TrackMouseEvent)
1744     GET_PROC(user32, UnhookWinEvent)
1745     GET_PROC(user32, GetMonitorInfoA)
1746     GET_PROC(user32, MonitorFromPoint)
1747
1748     GET_PROC(kernel32, GetCPInfoExA)
1749
1750 #undef GET_PROC
1751 }
1752
1753 static const char *get_winpos_flags(UINT flags)
1754 {
1755     static char buffer[300];
1756
1757     buffer[0] = 0;
1758 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1759     DUMP( SWP_SHOWWINDOW );
1760     DUMP( SWP_HIDEWINDOW );
1761     DUMP( SWP_NOACTIVATE );
1762     DUMP( SWP_FRAMECHANGED );
1763     DUMP( SWP_NOCOPYBITS );
1764     DUMP( SWP_NOOWNERZORDER );
1765     DUMP( SWP_NOSENDCHANGING );
1766     DUMP( SWP_DEFERERASE );
1767     DUMP( SWP_ASYNCWINDOWPOS );
1768     DUMP( SWP_NOZORDER );
1769     DUMP( SWP_NOREDRAW );
1770     DUMP( SWP_NOSIZE );
1771     DUMP( SWP_NOMOVE );
1772     DUMP( SWP_NOCLIENTSIZE );
1773     DUMP( SWP_NOCLIENTMOVE );
1774     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1775     return buffer + 1;
1776 #undef DUMP
1777 }
1778
1779 static BOOL ignore_message( UINT message )
1780 {
1781     /* these are always ignored */
1782     return (message >= 0xc000 ||
1783             message == WM_GETICON ||
1784             message == WM_GETOBJECT ||
1785             message == WM_TIMECHANGE ||
1786             message == WM_DISPLAYCHANGE ||
1787             message == WM_DEVICECHANGE ||
1788             message == WM_DWMNCRENDERINGCHANGED);
1789 }
1790
1791
1792 #define add_message(msg) add_message_(__LINE__,msg);
1793 static void add_message_(int line, const struct recvd_message *msg)
1794 {
1795     struct recvd_message *seq;
1796
1797     if (!sequence) 
1798     {
1799         sequence_size = 10;
1800         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1801     }
1802     if (sequence_cnt == sequence_size) 
1803     {
1804         sequence_size *= 2;
1805         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1806     }
1807     assert(sequence);
1808
1809     seq = &sequence[sequence_cnt];
1810     seq->hwnd = msg->hwnd;
1811     seq->message = msg->message;
1812     seq->flags = msg->flags;
1813     seq->wParam = msg->wParam;
1814     seq->lParam = msg->lParam;
1815     seq->line   = line;
1816     seq->descr  = msg->descr;
1817     seq->output[0] = 0;
1818
1819     if (msg->descr)
1820     {
1821         if (msg->flags & hook)
1822         {
1823             static const char * const CBT_code_name[10] =
1824             {
1825                 "HCBT_MOVESIZE",
1826                 "HCBT_MINMAX",
1827                 "HCBT_QS",
1828                 "HCBT_CREATEWND",
1829                 "HCBT_DESTROYWND",
1830                 "HCBT_ACTIVATE",
1831                 "HCBT_CLICKSKIPPED",
1832                 "HCBT_KEYSKIPPED",
1833                 "HCBT_SYSCOMMAND",
1834                 "HCBT_SETFOCUS"
1835             };
1836             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1837
1838             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1839                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1840         }
1841         else if (msg->flags & winevent_hook)
1842         {
1843             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1844                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1845         }
1846         else
1847         {
1848             switch (msg->message)
1849             {
1850             case WM_WINDOWPOSCHANGING:
1851             case WM_WINDOWPOSCHANGED:
1852             {
1853                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1854
1855                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1856                           msg->descr, msg->hwnd,
1857                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1858                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1859                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1860                           get_winpos_flags(winpos->flags) );
1861
1862                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1863                  * in the high word for internal purposes
1864                  */
1865                 seq->wParam = winpos->flags & 0xffff;
1866                 /* We are not interested in the flags that don't match under XP and Win9x */
1867                 seq->wParam &= ~SWP_NOZORDER;
1868                 break;
1869             }
1870
1871             case WM_DRAWITEM:
1872             {
1873                 DRAW_ITEM_STRUCT di;
1874                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1875
1876                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1877                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1878                          dis->itemID, dis->itemAction, dis->itemState);
1879
1880                 di.u.lp = 0;
1881                 di.u.item.type = dis->CtlType;
1882                 di.u.item.ctl_id = dis->CtlID;
1883                 if (dis->CtlType == ODT_LISTBOX ||
1884                     dis->CtlType == ODT_COMBOBOX ||
1885                     dis->CtlType == ODT_MENU)
1886                     di.u.item.item_id = dis->itemID;
1887                 di.u.item.action = dis->itemAction;
1888                 di.u.item.state = dis->itemState;
1889
1890                 seq->lParam = di.u.lp;
1891                 break;
1892             }
1893             default:
1894                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1895                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1896                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1897             }
1898             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1899                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1900         }
1901     }
1902
1903     sequence_cnt++;
1904 }
1905
1906 /* try to make sure pending X events have been processed before continuing */
1907 static void flush_events(void)
1908 {
1909     MSG msg;
1910     int diff = 200;
1911     int min_timeout = 100;
1912     DWORD time = GetTickCount() + diff;
1913
1914     while (diff > 0)
1915     {
1916         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1917         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1918         diff = time - GetTickCount();
1919     }
1920 }
1921
1922 static void flush_sequence(void)
1923 {
1924     HeapFree(GetProcessHeap(), 0, sequence);
1925     sequence = 0;
1926     sequence_cnt = sequence_size = 0;
1927 }
1928
1929 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1930 {
1931     const struct recvd_message *actual = sequence;
1932     unsigned int count = 0;
1933
1934     trace_(file, line)("Failed sequence %s:\n", context );
1935     while (expected->message && actual->message)
1936     {
1937         if (actual->output[0])
1938         {
1939             if (expected->flags & hook)
1940             {
1941                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1942                                     count, expected->message, actual->output );
1943             }
1944             else if (expected->flags & winevent_hook)
1945             {
1946                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1947                                     count, expected->message, actual->output );
1948             }
1949             else if (expected->flags & kbd_hook)
1950             {
1951                 trace_(file, line)( "  %u: expected: kbd %04x - actual: %s\n",
1952                                     count, expected->message, actual->output );
1953             }
1954             else
1955             {
1956                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1957                                     count, expected->message, actual->output );
1958             }
1959         }
1960
1961         if (expected->message == actual->message)
1962         {
1963             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1964                 (expected->flags & optional))
1965             {
1966                 /* don't match messages if their defwinproc status differs */
1967                 expected++;
1968             }
1969             else
1970             {
1971                 expected++;
1972                 actual++;
1973             }
1974         }
1975         /* silently drop winevent messages if there is no support for them */
1976         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1977             expected++;
1978         else
1979         {
1980             expected++;
1981             actual++;
1982         }
1983         count++;
1984     }
1985
1986     /* optional trailing messages */
1987     while (expected->message && ((expected->flags & optional) ||
1988             ((expected->flags & winevent_hook) && !hEvent_hook)))
1989     {
1990         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1991         expected++;
1992         count++;
1993     }
1994
1995     if (expected->message)
1996     {
1997         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1998         return;
1999     }
2000
2001     while (actual->message && actual->output[0])
2002     {
2003         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
2004         actual++;
2005         count++;
2006     }
2007 }
2008
2009 #define ok_sequence( exp, contx, todo) \
2010         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2011
2012
2013 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
2014                          const char *file, int line)
2015 {
2016     static const struct recvd_message end_of_sequence;
2017     const struct message *expected = expected_list;
2018     const struct recvd_message *actual;
2019     int failcount = 0, dump = 0;
2020     unsigned int count = 0;
2021
2022     add_message(&end_of_sequence);
2023
2024     actual = sequence;
2025
2026     while (expected->message && actual->message)
2027     {
2028         if (expected->message == actual->message &&
2029             !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2030         {
2031             if (expected->flags & wparam)
2032             {
2033                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2034                 {
2035                     todo_wine {
2036                         failcount ++;
2037                         if (strcmp(winetest_platform, "wine")) dump++;
2038                         ok_( file, line) (FALSE,
2039                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2040                             context, count, expected->message, expected->wParam, actual->wParam);
2041                     }
2042                 }
2043                 else
2044                 {
2045                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2046                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2047                                      context, count, expected->message, expected->wParam, actual->wParam);
2048                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2049                 }
2050
2051             }
2052             if (expected->flags & lparam)
2053             {
2054                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2055                 {
2056                     todo_wine {
2057                         failcount ++;
2058                         if (strcmp(winetest_platform, "wine")) dump++;
2059                         ok_( file, line) (FALSE,
2060                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2061                             context, count, expected->message, expected->lParam, actual->lParam);
2062                     }
2063                 }
2064                 else
2065                 {
2066                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2067                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2068                                      context, count, expected->message, expected->lParam, actual->lParam);
2069                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2070                 }
2071             }
2072             if ((expected->flags & optional) &&
2073                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2074             {
2075                 /* don't match optional messages if their defwinproc or parent status differs */
2076                 expected++;
2077                 count++;
2078                 continue;
2079             }
2080             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2081             {
2082                     todo_wine {
2083                         failcount ++;
2084                         if (strcmp(winetest_platform, "wine")) dump++;
2085                         ok_( file, line) (FALSE,
2086                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2087                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2088                     }
2089             }
2090             else
2091             {
2092                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2093                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2094                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2095                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2096             }
2097
2098             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2099                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2100                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2101             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2102
2103             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2104                 "%s: %u: the msg 0x%04x should have been %s\n",
2105                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2106             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2107
2108             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2109                 "%s: %u: the msg 0x%04x was expected in %s\n",
2110                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2111             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2112
2113             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2114                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2115                 context, count, expected->message);
2116             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2117
2118             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2119                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2120                 context, count, expected->message);
2121             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2122
2123             ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2124                 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2125                 context, count, expected->message);
2126             if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2127
2128             expected++;
2129             actual++;
2130         }
2131         /* silently drop hook messages if there is no support for them */
2132         else if ((expected->flags & optional) ||
2133                  ((expected->flags & hook) && !hCBT_hook) ||
2134                  ((expected->flags & winevent_hook) && !hEvent_hook) ||
2135                  ((expected->flags & kbd_hook) && !hKBD_hook))
2136             expected++;
2137         else if (todo)
2138         {
2139             failcount++;
2140             todo_wine {
2141                 if (strcmp(winetest_platform, "wine")) dump++;
2142                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2143                                   context, count, expected->message, actual->message);
2144             }
2145             goto done;
2146         }
2147         else
2148         {
2149             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2150                               context, count, expected->message, actual->message);
2151             dump++;
2152             expected++;
2153             actual++;
2154         }
2155         count++;
2156     }
2157
2158     /* skip all optional trailing messages */
2159     while (expected->message && ((expected->flags & optional) ||
2160                                  ((expected->flags & hook) && !hCBT_hook) ||
2161                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2162         expected++;
2163
2164     if (todo)
2165     {
2166         todo_wine {
2167             if (expected->message || actual->message) {
2168                 failcount++;
2169                 if (strcmp(winetest_platform, "wine")) dump++;
2170                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2171                                   context, count, expected->message, actual->message);
2172             }
2173         }
2174     }
2175     else
2176     {
2177         if (expected->message || actual->message)
2178         {
2179             dump++;
2180             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2181                               context, count, expected->message, actual->message);
2182         }
2183     }
2184     if( todo && !failcount) /* succeeded yet marked todo */
2185         todo_wine {
2186             if (!strcmp(winetest_platform, "wine")) dump++;
2187             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2188         }
2189
2190 done:
2191     if (dump) dump_sequence(expected_list, context, file, line);
2192     flush_sequence();
2193 }
2194
2195 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2196
2197 /******************************** MDI test **********************************/
2198
2199 /* CreateWindow for MDI frame window, initially visible */
2200 static const struct message WmCreateMDIframeSeq[] = {
2201     { HCBT_CREATEWND, hook },
2202     { WM_GETMINMAXINFO, sent },
2203     { WM_NCCREATE, sent },
2204     { WM_NCCALCSIZE, sent|wparam, 0 },
2205     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2206     { WM_CREATE, sent },
2207     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2208     { WM_NOTIFYFORMAT, sent|optional },
2209     { WM_QUERYUISTATE, sent|optional },
2210     { WM_WINDOWPOSCHANGING, sent|optional },
2211     { WM_GETMINMAXINFO, sent|optional },
2212     { WM_NCCALCSIZE, sent|optional },
2213     { WM_WINDOWPOSCHANGED, sent|optional },
2214     { WM_SHOWWINDOW, sent|wparam, 1 },
2215     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2216     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2217     { HCBT_ACTIVATE, hook },
2218     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2219     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2220     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2221     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2222     { WM_NCACTIVATE, sent },
2223     { WM_GETTEXT, sent|defwinproc|optional },
2224     { WM_ACTIVATE, sent|wparam, 1 },
2225     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2226     { HCBT_SETFOCUS, hook },
2227     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2228     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2229     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2230     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2231     /* Win9x adds SWP_NOZORDER below */
2232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2233     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2234     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2235     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2236     { WM_MOVE, sent },
2237     { 0 }
2238 };
2239 /* DestroyWindow for MDI frame window, initially visible */
2240 static const struct message WmDestroyMDIframeSeq[] = {
2241     { HCBT_DESTROYWND, hook },
2242     { 0x0090, sent|optional },
2243     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2244     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2245     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2246     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2247     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2248     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2249     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2250     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2251     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2252     { WM_DESTROY, sent },
2253     { WM_NCDESTROY, sent },
2254     { 0 }
2255 };
2256 /* CreateWindow for MDI client window, initially visible */
2257 static const struct message WmCreateMDIclientSeq[] = {
2258     { HCBT_CREATEWND, hook },
2259     { WM_NCCREATE, sent },
2260     { WM_NCCALCSIZE, sent|wparam, 0 },
2261     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2262     { WM_CREATE, sent },
2263     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2264     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2265     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2266     { WM_MOVE, sent },
2267     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2268     { WM_SHOWWINDOW, sent|wparam, 1 },
2269     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2270     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2271     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2272     { 0 }
2273 };
2274 /* ShowWindow(SW_SHOW) for MDI client window */
2275 static const struct message WmShowMDIclientSeq[] = {
2276     { WM_SHOWWINDOW, sent|wparam, 1 },
2277     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2278     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2279     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2280     { 0 }
2281 };
2282 /* ShowWindow(SW_HIDE) for MDI client window */
2283 static const struct message WmHideMDIclientSeq[] = {
2284     { WM_SHOWWINDOW, sent|wparam, 0 },
2285     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2286     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2287     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2288     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2289     { 0 }
2290 };
2291 /* DestroyWindow for MDI client window, initially visible */
2292 static const struct message WmDestroyMDIclientSeq[] = {
2293     { HCBT_DESTROYWND, hook },
2294     { 0x0090, sent|optional },
2295     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2296     { WM_SHOWWINDOW, sent|wparam, 0 },
2297     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2298     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2299     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2300     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2301     { WM_DESTROY, sent },
2302     { WM_NCDESTROY, sent },
2303     { 0 }
2304 };
2305 /* CreateWindow for MDI child window, initially visible */
2306 static const struct message WmCreateMDIchildVisibleSeq[] = {
2307     { HCBT_CREATEWND, hook },
2308     { WM_NCCREATE, sent }, 
2309     { WM_NCCALCSIZE, sent|wparam, 0 },
2310     { WM_CREATE, sent },
2311     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2312     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2313     { WM_MOVE, sent },
2314     /* Win2k sends wparam set to
2315      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2316      * while Win9x doesn't bother to set child window id according to
2317      * CLIENTCREATESTRUCT.idFirstChild
2318      */
2319     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2320     { WM_SHOWWINDOW, sent|wparam, 1 },
2321     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2322     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2323     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2324     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2326     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2327     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2328
2329     /* Win9x: message sequence terminates here. */
2330
2331     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2332     { HCBT_SETFOCUS, hook }, /* in MDI client */
2333     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2334     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2335     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2336     { WM_SETFOCUS, sent }, /* in MDI client */
2337     { HCBT_SETFOCUS, hook },
2338     { WM_KILLFOCUS, sent }, /* in MDI client */
2339     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2340     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2341     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2342     { WM_SETFOCUS, sent|defwinproc },
2343     { WM_MDIACTIVATE, sent|defwinproc },
2344     { 0 }
2345 };
2346 /* CreateWindow for MDI child window with invisible parent */
2347 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2348     { HCBT_CREATEWND, hook },
2349     { WM_GETMINMAXINFO, sent },
2350     { WM_NCCREATE, sent }, 
2351     { WM_NCCALCSIZE, sent|wparam, 0 },
2352     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2353     { WM_CREATE, sent },
2354     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2355     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2356     { WM_MOVE, sent },
2357     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2358     { WM_SHOWWINDOW, sent|wparam, 1 },
2359     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2360     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2361     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2362     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2363
2364     /* Win9x: message sequence terminates here. */
2365
2366     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2367     { HCBT_SETFOCUS, hook }, /* in MDI client */
2368     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2369     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2370     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2371     { WM_SETFOCUS, sent }, /* in MDI client */
2372     { HCBT_SETFOCUS, hook },
2373     { WM_KILLFOCUS, sent }, /* in MDI client */
2374     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2375     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2376     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2377     { WM_SETFOCUS, sent|defwinproc },
2378     { WM_MDIACTIVATE, sent|defwinproc },
2379     { 0 }
2380 };
2381 /* DestroyWindow for MDI child window, initially visible */
2382 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2383     { HCBT_DESTROYWND, hook },
2384     /* Win2k sends wparam set to
2385      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2386      * while Win9x doesn't bother to set child window id according to
2387      * CLIENTCREATESTRUCT.idFirstChild
2388      */
2389     { 0x0090, sent|optional },
2390     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2391     { WM_SHOWWINDOW, sent|wparam, 0 },
2392     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2393     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2394     { WM_ERASEBKGND, sent|parent|optional },
2395     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2396
2397     /* { WM_DESTROY, sent }
2398      * Win9x: message sequence terminates here.
2399      */
2400
2401     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2402     { WM_KILLFOCUS, sent },
2403     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2404     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2405     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2406     { WM_SETFOCUS, sent }, /* in MDI client */
2407
2408     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2409     { WM_KILLFOCUS, sent }, /* in MDI client */
2410     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2411     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2412     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2413     { WM_SETFOCUS, sent }, /* in MDI client */
2414
2415     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2416
2417     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2418     { WM_KILLFOCUS, sent },
2419     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2420     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2421     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2422     { WM_SETFOCUS, sent }, /* in MDI client */
2423
2424     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2425     { WM_KILLFOCUS, sent }, /* in MDI client */
2426     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2427     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2428     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2429     { WM_SETFOCUS, sent }, /* in MDI client */
2430
2431     { WM_DESTROY, sent },
2432
2433     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2434     { WM_KILLFOCUS, sent },
2435     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2436     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2437     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2438     { WM_SETFOCUS, sent }, /* in MDI client */
2439
2440     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2441     { WM_KILLFOCUS, sent }, /* in MDI client */
2442     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2443     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2444     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2445     { WM_SETFOCUS, sent }, /* in MDI client */
2446
2447     { WM_NCDESTROY, sent },
2448     { 0 }
2449 };
2450 /* CreateWindow for MDI child window, initially invisible */
2451 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2452     { HCBT_CREATEWND, hook },
2453     { WM_NCCREATE, sent }, 
2454     { WM_NCCALCSIZE, sent|wparam, 0 },
2455     { WM_CREATE, sent },
2456     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2457     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2458     { WM_MOVE, sent },
2459     /* Win2k sends wparam set to
2460      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2461      * while Win9x doesn't bother to set child window id according to
2462      * CLIENTCREATESTRUCT.idFirstChild
2463      */
2464     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2465     { 0 }
2466 };
2467 /* DestroyWindow for MDI child window, initially invisible */
2468 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2469     { HCBT_DESTROYWND, hook },
2470     /* Win2k sends wparam set to
2471      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2472      * while Win9x doesn't bother to set child window id according to
2473      * CLIENTCREATESTRUCT.idFirstChild
2474      */
2475     { 0x0090, sent|optional },
2476     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2477     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2478     { WM_DESTROY, sent },
2479     { WM_NCDESTROY, sent },
2480     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2481     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2482     { 0 }
2483 };
2484 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2485 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2486     { HCBT_CREATEWND, hook },
2487     { WM_NCCREATE, sent }, 
2488     { WM_NCCALCSIZE, sent|wparam, 0 },
2489     { WM_CREATE, sent },
2490     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2491     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2492     { WM_MOVE, sent },
2493     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2494     { WM_GETMINMAXINFO, sent },
2495     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2496     { WM_NCCALCSIZE, sent|wparam, 1 },
2497     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2498     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2499      /* in MDI frame */
2500     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2501     { WM_NCCALCSIZE, sent|wparam, 1 },
2502     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2503     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2504     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2505     /* Win2k sends wparam set to
2506      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2507      * while Win9x doesn't bother to set child window id according to
2508      * CLIENTCREATESTRUCT.idFirstChild
2509      */
2510     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2511     { WM_SHOWWINDOW, sent|wparam, 1 },
2512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2513     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2514     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2515     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2516     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2517     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2518     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2519
2520     /* Win9x: message sequence terminates here. */
2521
2522     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2523     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2524     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2525     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2526     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2527     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2528     { HCBT_SETFOCUS, hook|optional },
2529     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2530     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2531     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2532     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2533     { WM_SETFOCUS, sent|defwinproc|optional },
2534     { WM_MDIACTIVATE, sent|defwinproc|optional },
2535      /* in MDI frame */
2536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2537     { WM_NCCALCSIZE, sent|wparam, 1 },
2538     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2539     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2540     { 0 }
2541 };
2542 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2543 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2544     /* restore the 1st MDI child */
2545     { WM_SETREDRAW, sent|wparam, 0 },
2546     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2547     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2548     { WM_NCCALCSIZE, sent|wparam, 1 },
2549     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2550     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2551     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2552      /* in MDI frame */
2553     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2554     { WM_NCCALCSIZE, sent|wparam, 1 },
2555     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2556     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2557     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2558     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2559     /* create the 2nd MDI child */
2560     { HCBT_CREATEWND, hook },
2561     { WM_NCCREATE, sent }, 
2562     { WM_NCCALCSIZE, sent|wparam, 0 },
2563     { WM_CREATE, sent },
2564     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2565     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2566     { WM_MOVE, sent },
2567     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2568     { WM_GETMINMAXINFO, sent },
2569     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2570     { WM_NCCALCSIZE, sent|wparam, 1 },
2571     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2572     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2573     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2574      /* in MDI frame */
2575     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2576     { WM_NCCALCSIZE, sent|wparam, 1 },
2577     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2578     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2579     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2580     /* Win2k sends wparam set to
2581      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2582      * while Win9x doesn't bother to set child window id according to
2583      * CLIENTCREATESTRUCT.idFirstChild
2584      */
2585     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2586     { WM_SHOWWINDOW, sent|wparam, 1 },
2587     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2588     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2589     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2590     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2591     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2592     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2593
2594     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2595     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2596
2597     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2598
2599     /* Win9x: message sequence terminates here. */
2600
2601     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2602     { HCBT_SETFOCUS, hook },
2603     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2604     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2605     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2606     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2607     { WM_SETFOCUS, sent }, /* in MDI client */
2608     { HCBT_SETFOCUS, hook },
2609     { WM_KILLFOCUS, sent }, /* in MDI client */
2610     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2611     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2612     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2613     { WM_SETFOCUS, sent|defwinproc },
2614
2615     { WM_MDIACTIVATE, sent|defwinproc },
2616      /* in MDI frame */
2617     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2618     { WM_NCCALCSIZE, sent|wparam, 1 },
2619     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2620     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2621     { 0 }
2622 };
2623 /* WM_MDICREATE MDI child window, initially visible and maximized */
2624 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2625     { WM_MDICREATE, sent },
2626     { HCBT_CREATEWND, hook },
2627     { WM_NCCREATE, sent }, 
2628     { WM_NCCALCSIZE, sent|wparam, 0 },
2629     { WM_CREATE, sent },
2630     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2631     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2632     { WM_MOVE, sent },
2633     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2634     { WM_GETMINMAXINFO, sent },
2635     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2636     { WM_NCCALCSIZE, sent|wparam, 1 },
2637     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2638     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2639
2640      /* in MDI frame */
2641     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2642     { WM_NCCALCSIZE, sent|wparam, 1 },
2643     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2644     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2645     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2646
2647     /* Win2k sends wparam set to
2648      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2649      * while Win9x doesn't bother to set child window id according to
2650      * CLIENTCREATESTRUCT.idFirstChild
2651      */
2652     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2653     { WM_SHOWWINDOW, sent|wparam, 1 },
2654     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2655
2656     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2657
2658     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2659     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2660     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2661
2662     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2663     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2664
2665     /* Win9x: message sequence terminates here. */
2666
2667     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2668     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2669     { HCBT_SETFOCUS, hook }, /* in MDI client */
2670     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2671     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2672     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2673     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2674     { HCBT_SETFOCUS, hook|optional },
2675     { WM_KILLFOCUS, sent }, /* in MDI client */
2676     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2677     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2678     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2679     { WM_SETFOCUS, sent|defwinproc },
2680
2681     { WM_MDIACTIVATE, sent|defwinproc },
2682
2683      /* in MDI child */
2684     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2685     { WM_NCCALCSIZE, sent|wparam, 1 },
2686     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2687     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2688
2689      /* in MDI frame */
2690     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2691     { WM_NCCALCSIZE, sent|wparam, 1 },
2692     { 0x0093, sent|defwinproc|optional },
2693     { 0x0093, sent|defwinproc|optional },
2694     { 0x0093, sent|defwinproc|optional },
2695     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2696     { WM_MOVE, sent|defwinproc },
2697     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2698
2699      /* in MDI client */
2700     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2701     { WM_NCCALCSIZE, sent|wparam, 1 },
2702     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2703     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2704
2705      /* in MDI child */
2706     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2707     { WM_NCCALCSIZE, sent|wparam, 1 },
2708     { 0x0093, sent|optional },
2709     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2710     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2711
2712     { 0x0093, sent|optional },
2713     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2714     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2715     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2716     { 0x0093, sent|defwinproc|optional },
2717     { 0x0093, sent|defwinproc|optional },
2718     { 0x0093, sent|defwinproc|optional },
2719     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2720     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2721
2722     { 0 }
2723 };
2724 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2725 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2726     { HCBT_CREATEWND, hook },
2727     { WM_GETMINMAXINFO, sent },
2728     { WM_NCCREATE, sent }, 
2729     { WM_NCCALCSIZE, sent|wparam, 0 },
2730     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2731     { WM_CREATE, sent },
2732     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2733     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2734     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2735     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2736     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2737     { WM_MOVE, sent },
2738     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2739     { WM_GETMINMAXINFO, sent },
2740     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2741     { WM_GETMINMAXINFO, sent|defwinproc },
2742     { WM_NCCALCSIZE, sent|wparam, 1 },
2743     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2744     { WM_MOVE, sent|defwinproc },
2745     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2746      /* in MDI frame */
2747     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2748     { WM_NCCALCSIZE, sent|wparam, 1 },
2749     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2750     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2751     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2752     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2753     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2754     /* Win2k sends wparam set to
2755      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2756      * while Win9x doesn't bother to set child window id according to
2757      * CLIENTCREATESTRUCT.idFirstChild
2758      */
2759     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2760     { 0 }
2761 };
2762 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2763 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2764     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2765     { HCBT_SYSCOMMAND, hook },
2766     { WM_CLOSE, sent|defwinproc },
2767     { WM_MDIDESTROY, sent }, /* in MDI client */
2768
2769     /* bring the 1st MDI child to top */
2770     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2771     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2772
2773     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2774
2775     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2776     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2777     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2778
2779     /* maximize the 1st MDI child */
2780     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2781     { WM_GETMINMAXINFO, sent|defwinproc },
2782     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2783     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2784     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2785     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2786     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2787
2788     /* restore the 2nd MDI child */
2789     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2790     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2791     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2792     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2793
2794     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2795
2796     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2797     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2798
2799     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2800
2801     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2802      /* in MDI frame */
2803     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2804     { WM_NCCALCSIZE, sent|wparam, 1 },
2805     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2806     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2807     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2808
2809     /* bring the 1st MDI child to top */
2810     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2811     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2812     { HCBT_SETFOCUS, hook },
2813     { WM_KILLFOCUS, sent|defwinproc },
2814     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2815     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2816     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2817     { WM_SETFOCUS, sent }, /* in MDI client */
2818     { HCBT_SETFOCUS, hook },
2819     { WM_KILLFOCUS, sent }, /* in MDI client */
2820     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2821     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2822     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2823     { WM_SETFOCUS, sent|defwinproc },
2824     { WM_MDIACTIVATE, sent|defwinproc },
2825     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2826
2827     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2828     { WM_SHOWWINDOW, sent|wparam, 1 },
2829     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2830     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2831     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2832     { WM_MDIREFRESHMENU, sent },
2833
2834     { HCBT_DESTROYWND, hook },
2835     /* Win2k sends wparam set to
2836      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2837      * while Win9x doesn't bother to set child window id according to
2838      * CLIENTCREATESTRUCT.idFirstChild
2839      */
2840     { 0x0090, sent|defwinproc|optional },
2841     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2842     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2843     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2844     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2845     { WM_ERASEBKGND, sent|parent|optional },
2846     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2847
2848     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2849     { WM_DESTROY, sent|defwinproc },
2850     { WM_NCDESTROY, sent|defwinproc },
2851     { 0 }
2852 };
2853 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2854 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2855     { WM_MDIDESTROY, sent }, /* in MDI client */
2856     { WM_SHOWWINDOW, sent|wparam, 0 },
2857     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2858     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2859     { WM_ERASEBKGND, sent|parent|optional },
2860     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2861
2862     { HCBT_SETFOCUS, hook },
2863     { WM_KILLFOCUS, sent },
2864     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2865     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2866     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2867     { WM_SETFOCUS, sent }, /* in MDI client */
2868     { HCBT_SETFOCUS, hook },
2869     { WM_KILLFOCUS, sent }, /* in MDI client */
2870     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2871     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2872     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2873     { WM_SETFOCUS, sent },
2874
2875      /* in MDI child */
2876     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2877     { WM_NCCALCSIZE, sent|wparam, 1 },
2878     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2879     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2880
2881      /* in MDI frame */
2882     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2883     { WM_NCCALCSIZE, sent|wparam, 1 },
2884     { 0x0093, sent|defwinproc|optional },
2885     { 0x0093, sent|defwinproc|optional },
2886     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2887     { WM_MOVE, sent|defwinproc },
2888     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2889
2890      /* in MDI client */
2891     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2892     { WM_NCCALCSIZE, sent|wparam, 1 },
2893     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2894     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2895
2896      /* in MDI child */
2897     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2898     { WM_NCCALCSIZE, sent|wparam, 1 },
2899     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2900     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2901
2902      /* in MDI child */
2903     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2904     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2905     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2906     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2907
2908      /* in MDI frame */
2909     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2910     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2911     { 0x0093, sent|defwinproc|optional },
2912     { 0x0093, sent|defwinproc|optional },
2913     { 0x0093, sent|defwinproc|optional },
2914     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2915     { WM_MOVE, sent|defwinproc },
2916     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2917
2918      /* in MDI client */
2919     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2920     { WM_NCCALCSIZE, sent|wparam, 1 },
2921     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2922     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2923
2924      /* in MDI child */
2925     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2926     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2927     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2928     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2929     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2930     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2931
2932     { 0x0093, sent|defwinproc|optional },
2933     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2934     { 0x0093, sent|defwinproc|optional },
2935     { 0x0093, sent|defwinproc|optional },
2936     { 0x0093, sent|defwinproc|optional },
2937     { 0x0093, sent|optional },
2938
2939     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2940     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2942     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2943     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2944
2945      /* in MDI frame */
2946     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2947     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2948     { 0x0093, sent|defwinproc|optional },
2949     { 0x0093, sent|defwinproc|optional },
2950     { 0x0093, sent|defwinproc|optional },
2951     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2952     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2953     { 0x0093, sent|optional },
2954
2955     { WM_NCACTIVATE, sent|wparam, 0 },
2956     { WM_MDIACTIVATE, sent },
2957
2958     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2959     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2960     { WM_NCCALCSIZE, sent|wparam, 1 },
2961
2962     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2963
2964     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2965     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2966     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2967
2968      /* in MDI child */
2969     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2970     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2971     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2972     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2973
2974      /* in MDI frame */
2975     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2976     { WM_NCCALCSIZE, sent|wparam, 1 },
2977     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2978     { WM_MOVE, sent|defwinproc },
2979     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2980
2981      /* in MDI client */
2982     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2983     { WM_NCCALCSIZE, sent|wparam, 1 },
2984     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2985     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2986     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2987     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2988     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2989     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2990     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2991
2992     { HCBT_SETFOCUS, hook },
2993     { WM_KILLFOCUS, sent },
2994     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2995     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2996     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2997     { WM_SETFOCUS, sent }, /* in MDI client */
2998
2999     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3000
3001     { HCBT_DESTROYWND, hook },
3002     /* Win2k sends wparam set to
3003      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3004      * while Win9x doesn't bother to set child window id according to
3005      * CLIENTCREATESTRUCT.idFirstChild
3006      */
3007     { 0x0090, sent|optional },
3008     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3009
3010     { WM_SHOWWINDOW, sent|wparam, 0 },
3011     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3012     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3013     { WM_ERASEBKGND, sent|parent|optional },
3014     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3015
3016     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3017     { WM_DESTROY, sent },
3018     { WM_NCDESTROY, sent },
3019     { 0 }
3020 };
3021 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3022 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3023     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3024     { WM_GETMINMAXINFO, sent },
3025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3026     { WM_NCCALCSIZE, sent|wparam, 1 },
3027     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3028     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3029
3030     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3031     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3032     { HCBT_SETFOCUS, hook|optional },
3033     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3034     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3035     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3036     { HCBT_SETFOCUS, hook|optional },
3037     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3038     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3039     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3040     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3041     { WM_SETFOCUS, sent|optional|defwinproc },
3042     { WM_MDIACTIVATE, sent|optional|defwinproc },
3043     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3044     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3045      /* in MDI frame */
3046     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3047     { WM_NCCALCSIZE, sent|wparam, 1 },
3048     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3049     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3050     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3051     { 0 }
3052 };
3053 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3054 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3055     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3056     { WM_GETMINMAXINFO, sent },
3057     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3058     { WM_GETMINMAXINFO, sent|defwinproc },
3059     { WM_NCCALCSIZE, sent|wparam, 1 },
3060     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3061     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3062
3063     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3064     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3065     { HCBT_SETFOCUS, hook|optional },
3066     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3067     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3068     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3069     { HCBT_SETFOCUS, hook|optional },
3070     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3071     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3072     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3073     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3074     { WM_SETFOCUS, sent|defwinproc|optional },
3075     { WM_MDIACTIVATE, sent|defwinproc|optional },
3076     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3077     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3078     { 0 }
3079 };
3080 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3081 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3082     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3083     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3084     { WM_GETMINMAXINFO, sent },
3085     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3086     { WM_GETMINMAXINFO, sent|defwinproc },
3087     { WM_NCCALCSIZE, sent|wparam, 1 },
3088     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3089     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3090     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3091     { WM_MOVE, sent|defwinproc },
3092     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3093
3094     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3095     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3096     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3097     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3098     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3099     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3100      /* in MDI frame */
3101     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3102     { WM_NCCALCSIZE, sent|wparam, 1 },
3103     { 0x0093, sent|defwinproc|optional },
3104     { 0x0094, sent|defwinproc|optional },
3105     { 0x0094, sent|defwinproc|optional },
3106     { 0x0094, sent|defwinproc|optional },
3107     { 0x0094, sent|defwinproc|optional },
3108     { 0x0093, sent|defwinproc|optional },
3109     { 0x0093, sent|defwinproc|optional },
3110     { 0x0091, sent|defwinproc|optional },
3111     { 0x0092, sent|defwinproc|optional },
3112     { 0x0092, sent|defwinproc|optional },
3113     { 0x0092, sent|defwinproc|optional },
3114     { 0x0092, sent|defwinproc|optional },
3115     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3116     { WM_MOVE, sent|defwinproc },
3117     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3118     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3119      /* in MDI client */
3120     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3121     { WM_NCCALCSIZE, sent|wparam, 1 },
3122     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3123     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3124      /* in MDI child */
3125     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3126     { WM_GETMINMAXINFO, sent|defwinproc },
3127     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3128     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3129     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3130     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3131     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3132     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3133     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3134     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3135      /* in MDI frame */
3136     { 0x0093, sent|optional },
3137     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3138     { 0x0093, sent|defwinproc|optional },
3139     { 0x0093, sent|defwinproc|optional },
3140     { 0x0093, sent|defwinproc|optional },
3141     { 0x0091, sent|defwinproc|optional },
3142     { 0x0092, sent|defwinproc|optional },
3143     { 0x0092, sent|defwinproc|optional },
3144     { 0x0092, sent|defwinproc|optional },
3145     { 0x0092, sent|defwinproc|optional },
3146     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3147     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3148     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3149     { 0 }
3150 };
3151 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3152 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3153     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3154     { WM_GETMINMAXINFO, sent },
3155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3156     { WM_NCCALCSIZE, sent|wparam, 1 },
3157     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3158     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3159     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3160      /* in MDI frame */
3161     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3162     { WM_NCCALCSIZE, sent|wparam, 1 },
3163     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3164     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3165     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3166     { 0 }
3167 };
3168 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3169 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3170     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3171     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3172     { WM_NCCALCSIZE, sent|wparam, 1 },
3173     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3174     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3175     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3176      /* in MDI frame */
3177     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3178     { WM_NCCALCSIZE, sent|wparam, 1 },
3179     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3180     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3181     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3182     { 0 }
3183 };
3184 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3185 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3186     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3187     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3188     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3189     { WM_NCCALCSIZE, sent|wparam, 1 },
3190     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3191     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3192     { WM_MOVE, sent|defwinproc },
3193     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3194     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3195     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3196     { HCBT_SETFOCUS, hook },
3197     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3198     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3199     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3200     { WM_SETFOCUS, sent },
3201     { 0 }
3202 };
3203 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3204 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3205     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3206     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3207     { WM_NCCALCSIZE, sent|wparam, 1 },
3208     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3209     { WM_MOVE, sent|defwinproc },
3210     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3211     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3212     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3213     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3214     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3215     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3216     { 0 }
3217 };
3218 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3219 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3220     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3221     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3222     { WM_NCCALCSIZE, sent|wparam, 1 },
3223     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3224     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3225     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3226     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3227      /* in MDI frame */
3228     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3229     { WM_NCCALCSIZE, sent|wparam, 1 },
3230     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3231     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3232     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3233     { 0 }
3234 };
3235
3236 static HWND mdi_client;
3237 static WNDPROC old_mdi_client_proc;
3238
3239 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3240 {
3241     struct recvd_message msg;
3242
3243     /* do not log painting messages */
3244     if (message != WM_PAINT &&
3245         message != WM_NCPAINT &&
3246         message != WM_SYNCPAINT &&
3247         message != WM_ERASEBKGND &&
3248         message != WM_NCHITTEST &&
3249         message != WM_GETTEXT &&
3250         message != WM_MDIGETACTIVE &&
3251         !ignore_message( message ))
3252     {
3253         msg.hwnd = hwnd;
3254         msg.message = message;
3255         msg.flags = sent|wparam|lparam;
3256         msg.wParam = wParam;
3257         msg.lParam = lParam;
3258         msg.descr = "mdi client";
3259         add_message(&msg);
3260     }
3261
3262     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3263 }
3264
3265 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3266 {
3267     static LONG defwndproc_counter = 0;
3268     LRESULT ret;
3269     struct recvd_message msg;
3270
3271     /* do not log painting messages */
3272     if (message != WM_PAINT &&
3273         message != WM_NCPAINT &&
3274         message != WM_SYNCPAINT &&
3275         message != WM_ERASEBKGND &&
3276         message != WM_NCHITTEST &&
3277         message != WM_GETTEXT &&
3278         !ignore_message( message ))
3279     {
3280         switch (message)
3281         {
3282             case WM_MDIACTIVATE:
3283             {
3284                 HWND active, client = GetParent(hwnd);
3285
3286                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3287
3288                 if (hwnd == (HWND)lParam) /* if we are being activated */
3289                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3290                 else
3291                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3292                 break;
3293             }
3294         }
3295
3296         msg.hwnd = hwnd;
3297         msg.message = message;
3298         msg.flags = sent|wparam|lparam;
3299         if (defwndproc_counter) msg.flags |= defwinproc;
3300         msg.wParam = wParam;
3301         msg.lParam = lParam;
3302         msg.descr = "mdi child";
3303         add_message(&msg);
3304     }
3305
3306     defwndproc_counter++;
3307     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3308     defwndproc_counter--;
3309
3310     return ret;
3311 }
3312
3313 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3314 {
3315     static LONG defwndproc_counter = 0;
3316     LRESULT ret;
3317     struct recvd_message msg;
3318
3319     /* do not log painting messages */
3320     if (message != WM_PAINT &&
3321         message != WM_NCPAINT &&
3322         message != WM_SYNCPAINT &&
3323         message != WM_ERASEBKGND &&
3324         message != WM_NCHITTEST &&
3325         message != WM_GETTEXT &&
3326         !ignore_message( message ))
3327     {
3328         msg.hwnd = hwnd;
3329         msg.message = message;
3330         msg.flags = sent|wparam|lparam;
3331         if (defwndproc_counter) msg.flags |= defwinproc;
3332         msg.wParam = wParam;
3333         msg.lParam = lParam;
3334         msg.descr = "mdi frame";
3335         add_message(&msg);
3336     }
3337
3338     defwndproc_counter++;
3339     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3340     defwndproc_counter--;
3341
3342     return ret;
3343 }
3344
3345 static BOOL mdi_RegisterWindowClasses(void)
3346 {
3347     WNDCLASSA cls;
3348
3349     cls.style = 0;
3350     cls.lpfnWndProc = mdi_frame_wnd_proc;
3351     cls.cbClsExtra = 0;
3352     cls.cbWndExtra = 0;
3353     cls.hInstance = GetModuleHandleA(0);
3354     cls.hIcon = 0;
3355     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3356     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3357     cls.lpszMenuName = NULL;
3358     cls.lpszClassName = "MDI_frame_class";
3359     if (!RegisterClassA(&cls)) return FALSE;
3360
3361     cls.lpfnWndProc = mdi_child_wnd_proc;
3362     cls.lpszClassName = "MDI_child_class";
3363     if (!RegisterClassA(&cls)) return FALSE;
3364
3365     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3366     old_mdi_client_proc = cls.lpfnWndProc;
3367     cls.hInstance = GetModuleHandleA(0);
3368     cls.lpfnWndProc = mdi_client_hook_proc;
3369     cls.lpszClassName = "MDI_client_class";
3370     if (!RegisterClassA(&cls)) assert(0);
3371
3372     return TRUE;
3373 }
3374
3375 static void test_mdi_messages(void)
3376 {
3377     MDICREATESTRUCTA mdi_cs;
3378     CLIENTCREATESTRUCT client_cs;
3379     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3380     BOOL zoomed;
3381     RECT rc;
3382     HMENU hMenu = CreateMenu();
3383
3384     if (!mdi_RegisterWindowClasses()) assert(0);
3385
3386     flush_sequence();
3387
3388     trace("creating MDI frame window\n");
3389     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3390                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3391                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3392                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3393                                 GetDesktopWindow(), hMenu,
3394                                 GetModuleHandleA(0), NULL);
3395     assert(mdi_frame);
3396     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3397
3398     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3399     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3400
3401     trace("creating MDI client window\n");
3402     GetClientRect(mdi_frame, &rc);
3403     client_cs.hWindowMenu = 0;
3404     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3405     mdi_client = CreateWindowExA(0, "MDI_client_class",
3406                                  NULL,
3407                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3408                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3409                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3410     assert(mdi_client);
3411     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3412
3413     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3414     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3415
3416     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3417     ok(!active_child, "wrong active MDI child %p\n", active_child);
3418     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3419
3420     SetFocus(0);
3421     flush_sequence();
3422
3423     trace("creating invisible MDI child window\n");
3424     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3425                                 WS_CHILD,
3426                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3427                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3428     assert(mdi_child);
3429
3430     flush_sequence();
3431     ShowWindow(mdi_child, SW_SHOWNORMAL);
3432     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3433
3434     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3435     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3436
3437     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3438     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3439
3440     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3441     ok(!active_child, "wrong active MDI child %p\n", active_child);
3442     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3443
3444     ShowWindow(mdi_child, SW_HIDE);
3445     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3446     flush_sequence();
3447
3448     ShowWindow(mdi_child, SW_SHOW);
3449     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3450
3451     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3452     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3453
3454     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3455     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3456
3457     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3458     ok(!active_child, "wrong active MDI child %p\n", active_child);
3459     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3460
3461     DestroyWindow(mdi_child);
3462     flush_sequence();
3463
3464     trace("creating visible MDI child window\n");
3465     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3466                                 WS_CHILD | WS_VISIBLE,
3467                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3468                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3469     assert(mdi_child);
3470     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3471
3472     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3473     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3474
3475     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3476     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3477
3478     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3479     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3480     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3481     flush_sequence();
3482
3483     DestroyWindow(mdi_child);
3484     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3485
3486     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3487     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3488
3489     /* Win2k: MDI client still returns a just destroyed child as active
3490      * Win9x: MDI client returns 0
3491      */
3492     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3493     ok(active_child == mdi_child || /* win2k */
3494        !active_child, /* win9x */
3495        "wrong active MDI child %p\n", active_child);
3496     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3497
3498     flush_sequence();
3499
3500     trace("creating invisible MDI child window\n");
3501     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3502                                 WS_CHILD,
3503                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3504                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3505     assert(mdi_child2);
3506     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3507
3508     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3509     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3510
3511     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3512     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3513
3514     /* Win2k: MDI client still returns a just destroyed child as active
3515      * Win9x: MDI client returns mdi_child2
3516      */
3517     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3518     ok(active_child == mdi_child || /* win2k */
3519        active_child == mdi_child2, /* win9x */
3520        "wrong active MDI child %p\n", active_child);
3521     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3522     flush_sequence();
3523
3524     ShowWindow(mdi_child2, SW_MAXIMIZE);
3525     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3526
3527     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3528     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3529
3530     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3531     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3532     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3533     flush_sequence();
3534
3535     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3536     ok(GetFocus() == mdi_child2 || /* win2k */
3537        GetFocus() == 0, /* win9x */
3538        "wrong focus window %p\n", GetFocus());
3539
3540     SetFocus(0);
3541     flush_sequence();
3542
3543     ShowWindow(mdi_child2, SW_HIDE);
3544     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3545
3546     ShowWindow(mdi_child2, SW_RESTORE);
3547     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3548     flush_sequence();
3549
3550     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3551     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3552
3553     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3554     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3555     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3556     flush_sequence();
3557
3558     SetFocus(0);
3559     flush_sequence();
3560
3561     ShowWindow(mdi_child2, SW_HIDE);
3562     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3563
3564     ShowWindow(mdi_child2, SW_SHOW);
3565     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3566
3567     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3568     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3569
3570     ShowWindow(mdi_child2, SW_MAXIMIZE);
3571     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3572
3573     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3574     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3575
3576     ShowWindow(mdi_child2, SW_RESTORE);
3577     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3578
3579     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3580     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3581
3582     ShowWindow(mdi_child2, SW_MINIMIZE);
3583     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3584
3585     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3586     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3587
3588     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3589     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3590     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3591     flush_sequence();
3592
3593     ShowWindow(mdi_child2, SW_RESTORE);
3594     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3595
3596     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3597     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3598
3599     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3600     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3601     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3602     flush_sequence();
3603
3604     SetFocus(0);
3605     flush_sequence();
3606
3607     ShowWindow(mdi_child2, SW_HIDE);
3608     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3609
3610     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3611     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3612
3613     DestroyWindow(mdi_child2);
3614     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3615
3616     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3617     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3618
3619     /* test for maximized MDI children */
3620     trace("creating maximized visible MDI child window 1\n");
3621     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3622                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3623                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3624                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3625     assert(mdi_child);
3626     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3627     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3628
3629     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3630     ok(GetFocus() == mdi_child || /* win2k */
3631        GetFocus() == 0, /* win9x */
3632        "wrong focus window %p\n", GetFocus());
3633
3634     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3635     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3636     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3637     flush_sequence();
3638
3639     trace("creating maximized visible MDI child window 2\n");
3640     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3641                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3642                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3643                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3644     assert(mdi_child2);
3645     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3646     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3647     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3648
3649     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3650     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3651
3652     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3653     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3654     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3655     flush_sequence();
3656
3657     trace("destroying maximized visible MDI child window 2\n");
3658     DestroyWindow(mdi_child2);
3659     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3660
3661     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3662
3663     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3664     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3665
3666     /* Win2k: MDI client still returns a just destroyed child as active
3667      * Win9x: MDI client returns 0
3668      */
3669     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3670     ok(active_child == mdi_child2 || /* win2k */
3671        !active_child, /* win9x */
3672        "wrong active MDI child %p\n", active_child);
3673     flush_sequence();
3674
3675     ShowWindow(mdi_child, SW_MAXIMIZE);
3676     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3677     flush_sequence();
3678
3679     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3680     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3681
3682     trace("re-creating maximized visible MDI child window 2\n");
3683     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3684                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3685                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3686                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3687     assert(mdi_child2);
3688     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3689     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3690     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3691
3692     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3693     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3694
3695     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3696     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3697     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3698     flush_sequence();
3699
3700     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3701     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3702     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3703
3704     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3705     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3706     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3707
3708     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3709     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3710     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3711     flush_sequence();
3712
3713     DestroyWindow(mdi_child);
3714     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3715
3716     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3717     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3718
3719     /* Win2k: MDI client still returns a just destroyed child as active
3720      * Win9x: MDI client returns 0
3721      */
3722     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3723     ok(active_child == mdi_child || /* win2k */
3724        !active_child, /* win9x */
3725        "wrong active MDI child %p\n", active_child);
3726     flush_sequence();
3727
3728     trace("creating maximized invisible MDI child window\n");
3729     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3730                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3731                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3732                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3733     assert(mdi_child2);
3734     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3735     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3736     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3737     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3738
3739     /* Win2k: MDI client still returns a just destroyed child as active
3740      * Win9x: MDI client returns 0
3741      */
3742     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3743     ok(active_child == mdi_child || /* win2k */
3744        !active_child || active_child == mdi_child2, /* win9x */
3745        "wrong active MDI child %p\n", active_child);
3746     flush_sequence();
3747
3748     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3749     ShowWindow(mdi_child2, SW_MAXIMIZE);
3750     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3751     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3752     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3753     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3754
3755     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3756     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3757     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3758     flush_sequence();
3759
3760     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3761     flush_sequence();
3762
3763     /* end of test for maximized MDI children */
3764     SetFocus(0);
3765     flush_sequence();
3766     trace("creating maximized visible MDI child window 1(Switch test)\n");
3767     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3768                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3769                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3770                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3771     assert(mdi_child);
3772     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3773     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3774
3775     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3776     ok(GetFocus() == mdi_child || /* win2k */
3777        GetFocus() == 0, /* win9x */
3778        "wrong focus window %p(Switch test)\n", GetFocus());
3779
3780     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3781     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3782     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3783     flush_sequence();
3784
3785     trace("creating maximized visible MDI child window 2(Switch test)\n");
3786     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3787                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3788                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3789                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3790     assert(mdi_child2);
3791     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3792
3793     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3794     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3795
3796     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3797     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3798
3799     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3800     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3801     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3802     flush_sequence();
3803
3804     trace("Switch child window.\n");
3805     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3806     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3807     trace("end of test for switch maximized MDI children\n");
3808     flush_sequence();
3809
3810     /* Prepare for switching test of not maximized MDI children  */
3811     ShowWindow( mdi_child, SW_NORMAL );
3812     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3813     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3814     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3815     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3816     flush_sequence();
3817
3818     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3819     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3820     trace("end of test for switch not maximized MDI children\n");
3821     flush_sequence();
3822
3823     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3824     flush_sequence();
3825
3826     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3827     flush_sequence();
3828
3829     SetFocus(0);
3830     flush_sequence();
3831     /* end of tests for switch maximized/not maximized MDI children */
3832
3833     mdi_cs.szClass = "MDI_child_Class";
3834     mdi_cs.szTitle = "MDI child";
3835     mdi_cs.hOwner = GetModuleHandleA(0);
3836     mdi_cs.x = 0;
3837     mdi_cs.y = 0;
3838     mdi_cs.cx = CW_USEDEFAULT;
3839     mdi_cs.cy = CW_USEDEFAULT;
3840     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3841     mdi_cs.lParam = 0;
3842     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3843     ok(mdi_child != 0, "MDI child creation failed\n");
3844     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3845
3846     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3847
3848     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3849     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3850
3851     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3852     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3853     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3854
3855     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3856     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3857     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3858     flush_sequence();
3859
3860     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3861     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3862
3863     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3864     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3865     ok(!active_child, "wrong active MDI child %p\n", active_child);
3866
3867     SetFocus(0);
3868     flush_sequence();
3869
3870     DestroyWindow(mdi_client);
3871     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3872
3873     /* test maximization of MDI child with invisible parent */
3874     client_cs.hWindowMenu = 0;
3875     mdi_client = CreateWindow("MDI_client_class",
3876                                  NULL,
3877                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3878                                  0, 0, 660, 430,
3879                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3880     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3881
3882     ShowWindow(mdi_client, SW_HIDE);
3883     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3884
3885     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3886                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3887                                 0, 0, 650, 440,
3888                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3889     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3890
3891     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3892     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3893     zoomed = IsZoomed(mdi_child);
3894     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3895     
3896     ShowWindow(mdi_client, SW_SHOW);
3897     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3898
3899     DestroyWindow(mdi_child);
3900     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3901
3902     /* end of test for maximization of MDI child with invisible parent */
3903
3904     DestroyWindow(mdi_client);
3905     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3906
3907     DestroyWindow(mdi_frame);
3908     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3909 }
3910 /************************* End of MDI test **********************************/
3911
3912 static void test_WM_SETREDRAW(HWND hwnd)
3913 {
3914     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3915
3916     flush_events();
3917     flush_sequence();
3918
3919     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3920     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3921
3922     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3923     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3924
3925     flush_sequence();
3926     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3927     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3928
3929     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3930     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3931
3932     /* restore original WS_VISIBLE state */
3933     SetWindowLongA(hwnd, GWL_STYLE, style);
3934
3935     flush_events();
3936     flush_sequence();
3937 }
3938
3939 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3940 {
3941     struct recvd_message msg;
3942
3943     if (ignore_message( message )) return 0;
3944
3945     switch (message)
3946     {
3947         /* ignore */
3948         case WM_MOUSEMOVE:
3949         case WM_NCMOUSEMOVE:
3950         case WM_NCMOUSELEAVE:
3951         case WM_SETCURSOR:
3952             return 0;
3953         case WM_NCHITTEST:
3954             return HTCLIENT;
3955     }
3956
3957     msg.hwnd = hwnd;
3958     msg.message = message;
3959     msg.flags = sent|wparam|lparam;
3960     msg.wParam = wParam;
3961     msg.lParam = lParam;
3962     msg.descr = "dialog";
3963     add_message(&msg);
3964
3965     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3966     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3967     return 0;
3968 }
3969
3970 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3971 {
3972     DWORD style, exstyle;
3973     INT xmin, xmax;
3974     BOOL ret;
3975
3976     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3977     style = GetWindowLongA(hwnd, GWL_STYLE);
3978     /* do not be confused by WS_DLGFRAME set */
3979     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3980
3981     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3982     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3983
3984     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3985     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3986     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3987         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3988     else
3989         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3990
3991     style = GetWindowLongA(hwnd, GWL_STYLE);
3992     if (set) ok(style & set, "style %08x should be set\n", set);
3993     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3994
3995     /* a subsequent call should do nothing */
3996     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3997     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3998     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3999
4000     xmin = 0xdeadbeef;
4001     xmax = 0xdeadbeef;
4002     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4003     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4004     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4005     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4006     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4007 }
4008
4009 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4010 {
4011     DWORD style, exstyle;
4012     SCROLLINFO si;
4013     BOOL ret;
4014
4015     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4016     style = GetWindowLongA(hwnd, GWL_STYLE);
4017     /* do not be confused by WS_DLGFRAME set */
4018     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4019
4020     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4021     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4022
4023     si.cbSize = sizeof(si);
4024     si.fMask = SIF_RANGE;
4025     si.nMin = min;
4026     si.nMax = max;
4027     SetScrollInfo(hwnd, ctl, &si, TRUE);
4028     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4029         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4030     else
4031         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4032
4033     style = GetWindowLongA(hwnd, GWL_STYLE);
4034     if (set) ok(style & set, "style %08x should be set\n", set);
4035     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4036
4037     /* a subsequent call should do nothing */
4038     SetScrollInfo(hwnd, ctl, &si, TRUE);
4039     if (style & WS_HSCROLL)
4040         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4041     else if (style & WS_VSCROLL)
4042         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4043     else
4044         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4045
4046     si.fMask = SIF_PAGE;
4047     si.nPage = 5;
4048     SetScrollInfo(hwnd, ctl, &si, FALSE);
4049     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4050
4051     si.fMask = SIF_POS;
4052     si.nPos = max - 1;
4053     SetScrollInfo(hwnd, ctl, &si, FALSE);
4054     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4055
4056     si.fMask = SIF_RANGE;
4057     si.nMin = 0xdeadbeef;
4058     si.nMax = 0xdeadbeef;
4059     ret = GetScrollInfo(hwnd, ctl, &si);
4060     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4061     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4062     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4063     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4064 }
4065
4066 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4067 static void test_scroll_messages(HWND hwnd)
4068 {
4069     SCROLLINFO si;
4070     INT min, max;
4071     BOOL ret;
4072
4073     flush_events();
4074     flush_sequence();
4075
4076     min = 0xdeadbeef;
4077     max = 0xdeadbeef;
4078     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4079     ok( ret, "GetScrollRange error %d\n", GetLastError());
4080     if (sequence->message != WmGetScrollRangeSeq[0].message)
4081         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4082     /* values of min and max are undefined */
4083     flush_sequence();
4084
4085     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4086     ok( ret, "SetScrollRange error %d\n", GetLastError());
4087     if (sequence->message != WmSetScrollRangeSeq[0].message)
4088         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4089     flush_sequence();
4090
4091     min = 0xdeadbeef;
4092     max = 0xdeadbeef;
4093     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4094     ok( ret, "GetScrollRange error %d\n", GetLastError());
4095     if (sequence->message != WmGetScrollRangeSeq[0].message)
4096         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4097     /* values of min and max are undefined */
4098     flush_sequence();
4099
4100     si.cbSize = sizeof(si);
4101     si.fMask = SIF_RANGE;
4102     si.nMin = 20;
4103     si.nMax = 160;
4104     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4105     if (sequence->message != WmSetScrollRangeSeq[0].message)
4106         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4107     flush_sequence();
4108
4109     si.fMask = SIF_PAGE;
4110     si.nPage = 10;
4111     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4112     if (sequence->message != WmSetScrollRangeSeq[0].message)
4113         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4114     flush_sequence();
4115
4116     si.fMask = SIF_POS;
4117     si.nPos = 20;
4118     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4119     if (sequence->message != WmSetScrollRangeSeq[0].message)
4120         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4121     flush_sequence();
4122
4123     si.fMask = SIF_RANGE;
4124     si.nMin = 0xdeadbeef;
4125     si.nMax = 0xdeadbeef;
4126     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4127     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4128     if (sequence->message != WmGetScrollInfoSeq[0].message)
4129         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4130     /* values of min and max are undefined */
4131     flush_sequence();
4132
4133     /* set WS_HSCROLL */
4134     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4135     /* clear WS_HSCROLL */
4136     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4137
4138     /* set WS_HSCROLL */
4139     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4140     /* clear WS_HSCROLL */
4141     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4142
4143     /* set WS_VSCROLL */
4144     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4145     /* clear WS_VSCROLL */
4146     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4147
4148     /* set WS_VSCROLL */
4149     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4150     /* clear WS_VSCROLL */
4151     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4152 }
4153
4154 static void test_showwindow(void)
4155 {
4156     HWND hwnd, hchild;
4157     RECT rc;
4158
4159     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4160                            100, 100, 200, 200, 0, 0, 0, NULL);
4161     ok (hwnd != 0, "Failed to create overlapped window\n");
4162     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4163                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4164     ok (hchild != 0, "Failed to create child\n");
4165     flush_sequence();
4166
4167     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4168     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4169     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4170     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4171
4172     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4173     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4174     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4175     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4176     /* back to invisible */
4177     ShowWindow(hchild, SW_HIDE);
4178     ShowWindow(hwnd, SW_HIDE);
4179     flush_sequence();
4180     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4181     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4182     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4183     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4184     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4185     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4186     flush_sequence();
4187     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4188     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4189     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4190     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4191     ShowWindow( hwnd, SW_SHOW);
4192     flush_sequence();
4193     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4194     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4195     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4196
4197     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4198     ShowWindow( hchild, SW_HIDE);
4199     flush_sequence();
4200     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4201     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4202     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4203
4204     SetCapture(hchild);
4205     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4206     DestroyWindow(hchild);
4207     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4208
4209     DestroyWindow(hwnd);
4210     flush_sequence();
4211
4212     /* Popup windows */
4213     /* Test 1:
4214      * 1. Create invisible maximized popup window.
4215      * 2. Move and resize it.
4216      * 3. Show it maximized.
4217      */
4218     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4219     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4220                            100, 100, 200, 200, 0, 0, 0, NULL);
4221     ok (hwnd != 0, "Failed to create popup window\n");
4222     ok(IsZoomed(hwnd), "window should be maximized\n");
4223     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4224
4225     GetWindowRect(hwnd, &rc);
4226     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4227         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4228         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4229         rc.left, rc.top, rc.right, rc.bottom);
4230     /* Reset window's size & position */
4231     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4232     ok(IsZoomed(hwnd), "window should be maximized\n");
4233     flush_sequence();
4234
4235     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4236     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4237     ok(IsZoomed(hwnd), "window should be maximized\n");
4238     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4239
4240     GetWindowRect(hwnd, &rc);
4241     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4242         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4243         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4244         rc.left, rc.top, rc.right, rc.bottom);
4245     DestroyWindow(hwnd);
4246     flush_sequence();
4247
4248     /* Test 2:
4249      * 1. Create invisible maximized popup window.
4250      * 2. Show it maximized.
4251      */
4252     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4253     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4254                            100, 100, 200, 200, 0, 0, 0, NULL);
4255     ok (hwnd != 0, "Failed to create popup window\n");
4256     ok(IsZoomed(hwnd), "window should be maximized\n");
4257     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4258
4259     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4260     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4261     ok(IsZoomed(hwnd), "window should be maximized\n");
4262     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4263     DestroyWindow(hwnd);
4264     flush_sequence();
4265
4266     /* Test 3:
4267      * 1. Create visible maximized popup window.
4268      */
4269     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4270     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4271                            100, 100, 200, 200, 0, 0, 0, NULL);
4272     ok (hwnd != 0, "Failed to create popup window\n");
4273     ok(IsZoomed(hwnd), "window should be maximized\n");
4274     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4275     DestroyWindow(hwnd);
4276     flush_sequence();
4277
4278     /* Test 4:
4279      * 1. Create visible popup window.
4280      * 2. Maximize it.
4281      */
4282     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4283     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4284                            100, 100, 200, 200, 0, 0, 0, NULL);
4285     ok (hwnd != 0, "Failed to create popup window\n");
4286     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4287     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4288
4289     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4290     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4291     ok(IsZoomed(hwnd), "window should be maximized\n");
4292     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4293     DestroyWindow(hwnd);
4294     flush_sequence();
4295 }
4296
4297 static void test_sys_menu(void)
4298 {
4299     HWND hwnd;
4300     HMENU hmenu;
4301     UINT state;
4302
4303     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4304                            100, 100, 200, 200, 0, 0, 0, NULL);
4305     ok (hwnd != 0, "Failed to create overlapped window\n");
4306
4307     flush_sequence();
4308
4309     /* test existing window without CS_NOCLOSE style */
4310     hmenu = GetSystemMenu(hwnd, FALSE);
4311     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4312
4313     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4314     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4315     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4316
4317     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4318     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4319
4320     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4321     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4322     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4323
4324     EnableMenuItem(hmenu, SC_CLOSE, 0);
4325     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4326
4327     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4328     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4329     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4330
4331     /* test whether removing WS_SYSMENU destroys a system menu */
4332     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4333     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4334     flush_sequence();
4335     hmenu = GetSystemMenu(hwnd, FALSE);
4336     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4337
4338     DestroyWindow(hwnd);
4339
4340     /* test new window with CS_NOCLOSE style */
4341     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4342                            100, 100, 200, 200, 0, 0, 0, NULL);
4343     ok (hwnd != 0, "Failed to create overlapped window\n");
4344
4345     hmenu = GetSystemMenu(hwnd, FALSE);
4346     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4347
4348     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4349     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4350
4351     DestroyWindow(hwnd);
4352
4353     /* test new window without WS_SYSMENU style */
4354     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4355                            100, 100, 200, 200, 0, 0, 0, NULL);
4356     ok(hwnd != 0, "Failed to create overlapped window\n");
4357
4358     hmenu = GetSystemMenu(hwnd, FALSE);
4359     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4360
4361     DestroyWindow(hwnd);
4362 }
4363
4364 /* For shown WS_OVERLAPPEDWINDOW */
4365 static const struct message WmSetIcon_1[] = {
4366     { WM_SETICON, sent },
4367     { 0x00AE, sent|defwinproc|optional }, /* XP */
4368     { WM_GETTEXT, sent|defwinproc|optional },
4369     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4370     { 0 }
4371 };
4372
4373 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4374 static const struct message WmSetIcon_2[] = {
4375     { WM_SETICON, sent },
4376     { 0 }
4377 };
4378
4379 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4380 static const struct message WmInitEndSession[] = {
4381     { 0x003B, sent },
4382     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4383     { 0 }
4384 };
4385
4386 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4387 static const struct message WmInitEndSession_2[] = {
4388     { 0x003B, sent },
4389     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4390     { 0 }
4391 };
4392
4393 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4394 static const struct message WmInitEndSession_3[] = {
4395     { 0x003B, sent },
4396     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4397     { 0 }
4398 };
4399
4400 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4401 static const struct message WmInitEndSession_4[] = {
4402     { 0x003B, sent },
4403     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4404     { 0 }
4405 };
4406
4407 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4408 static const struct message WmInitEndSession_5[] = {
4409     { 0x003B, sent },
4410     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4411     { 0 }
4412 };
4413
4414 static const struct message WmOptionalPaint[] = {
4415     { WM_PAINT, sent|optional },
4416     { WM_NCPAINT, sent|beginpaint|optional },
4417     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4418     { WM_ERASEBKGND, sent|beginpaint|optional },
4419     { 0 }
4420 };
4421
4422 static const struct message WmZOrder[] = {
4423     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4424     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4425     { HCBT_ACTIVATE, hook },
4426     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4427     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4428     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4429     { WM_GETTEXT, sent|optional },
4430     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4431     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4432     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4433     { WM_GETTEXT, sent|defwinproc|optional },
4434     { WM_GETTEXT, sent|defwinproc|optional },
4435     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4436     { HCBT_SETFOCUS, hook },
4437     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4438     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4439     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4440     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4441     { WM_GETTEXT, sent|optional },
4442     { WM_NCCALCSIZE, sent|optional },
4443     { 0 }
4444 };
4445
4446 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4447 {
4448     DWORD ret;
4449     MSG msg;
4450
4451     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4452     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4453
4454     PostMessageA(hwnd, WM_USER, 0, 0);
4455
4456     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4457     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4458
4459     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4460     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4461
4462     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4463     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4464
4465     PostMessageA(hwnd, WM_USER, 0, 0);
4466
4467     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4468     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4469
4470     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4471     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4472
4473     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4474     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4475     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4476
4477     PostMessageA(hwnd, WM_USER, 0, 0);
4478
4479     /* new incoming message causes it to become signaled again */
4480     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4481     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4482
4483     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4484     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
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 }
4488
4489 /* test if we receive the right sequence of messages */
4490 static void test_messages(void)
4491 {
4492     HWND hwnd, hparent, hchild;
4493     HWND hchild2, hbutton;
4494     HMENU hmenu;
4495     MSG msg;
4496     LRESULT res;
4497
4498     flush_sequence();
4499
4500     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4501                            100, 100, 200, 200, 0, 0, 0, NULL);
4502     ok (hwnd != 0, "Failed to create overlapped window\n");
4503     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4504
4505     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4506     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4507     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4508
4509     /* test WM_SETREDRAW on a not visible top level window */
4510     test_WM_SETREDRAW(hwnd);
4511
4512     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4513     flush_events();
4514     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4515     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4516
4517     ok(GetActiveWindow() == hwnd, "window should be active\n");
4518     ok(GetFocus() == hwnd, "window should have input focus\n");
4519     ShowWindow(hwnd, SW_HIDE);
4520     flush_events();
4521     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4522
4523     ShowWindow(hwnd, SW_SHOW);
4524     flush_events();
4525     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4526
4527     ShowWindow(hwnd, SW_HIDE);
4528     flush_events();
4529     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4530
4531     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4532     flush_events();
4533     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4534     flush_sequence();
4535
4536     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4537     {
4538         ShowWindow(hwnd, SW_RESTORE);
4539         flush_events();
4540         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4541         flush_sequence();
4542     }
4543
4544     ShowWindow(hwnd, SW_MINIMIZE);
4545     flush_events();
4546     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4547     flush_sequence();
4548
4549     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4550     {
4551         ShowWindow(hwnd, SW_RESTORE);
4552         flush_events();
4553         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4554         flush_sequence();
4555     }
4556
4557     ShowWindow(hwnd, SW_SHOW);
4558     flush_events();
4559     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4560
4561     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4562     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4563     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4564     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4565
4566     /* test WM_SETREDRAW on a visible top level window */
4567     ShowWindow(hwnd, SW_SHOW);
4568     flush_events();
4569     test_WM_SETREDRAW(hwnd);
4570
4571     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4572     test_scroll_messages(hwnd);
4573
4574     /* test resizing and moving */
4575     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4576     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4577     flush_events();
4578     flush_sequence();
4579     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4580     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4581     flush_events();
4582     flush_sequence();
4583     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4584     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4585     flush_events();
4586     flush_sequence();
4587
4588     /* popups don't get WM_GETMINMAXINFO */
4589     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4590     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4591     flush_sequence();
4592     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4593     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4594
4595     DestroyWindow(hwnd);
4596     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4597
4598     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4599                               100, 100, 200, 200, 0, 0, 0, NULL);
4600     ok (hparent != 0, "Failed to create parent window\n");
4601     flush_sequence();
4602
4603     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4604                              0, 0, 10, 10, hparent, 0, 0, NULL);
4605     ok (hchild != 0, "Failed to create child window\n");
4606     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4607     DestroyWindow(hchild);
4608     flush_sequence();
4609
4610     /* visible child window with a caption */
4611     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4612                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4613                              0, 0, 10, 10, hparent, 0, 0, NULL);
4614     ok (hchild != 0, "Failed to create child window\n");
4615     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4616
4617     trace("testing scroll APIs on a visible child window %p\n", hchild);
4618     test_scroll_messages(hchild);
4619
4620     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4621     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4622
4623     DestroyWindow(hchild);
4624     flush_sequence();
4625
4626     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4627                              0, 0, 10, 10, hparent, 0, 0, NULL);
4628     ok (hchild != 0, "Failed to create child window\n");
4629     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4630     
4631     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4632                                100, 100, 50, 50, hparent, 0, 0, NULL);
4633     ok (hchild2 != 0, "Failed to create child2 window\n");
4634     flush_sequence();
4635
4636     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4637                               0, 100, 50, 50, hchild, 0, 0, NULL);
4638     ok (hbutton != 0, "Failed to create button window\n");
4639
4640     /* test WM_SETREDRAW on a not visible child window */
4641     test_WM_SETREDRAW(hchild);
4642
4643     ShowWindow(hchild, SW_SHOW);
4644     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4645
4646     /* check parent messages too */
4647     log_all_parent_messages++;
4648     ShowWindow(hchild, SW_HIDE);
4649     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4650     log_all_parent_messages--;
4651
4652     ShowWindow(hchild, SW_SHOW);
4653     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4654
4655     ShowWindow(hchild, SW_HIDE);
4656     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4657
4658     ShowWindow(hchild, SW_SHOW);
4659     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4660
4661     /* test WM_SETREDRAW on a visible child window */
4662     test_WM_SETREDRAW(hchild);
4663
4664     log_all_parent_messages++;
4665     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4666     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4667     log_all_parent_messages--;
4668
4669     ShowWindow(hchild, SW_HIDE);
4670     flush_sequence();
4671     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4672     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4673
4674     ShowWindow(hchild, SW_HIDE);
4675     flush_sequence();
4676     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4677     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4678
4679     /* DestroyWindow sequence below expects that a child has focus */
4680     SetFocus(hchild);
4681     flush_sequence();
4682
4683     DestroyWindow(hchild);
4684     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4685     DestroyWindow(hchild2);
4686     DestroyWindow(hbutton);
4687
4688     flush_sequence();
4689     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4690                              0, 0, 100, 100, hparent, 0, 0, NULL);
4691     ok (hchild != 0, "Failed to create child popup window\n");
4692     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4693     DestroyWindow(hchild);
4694
4695     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4696     flush_sequence();
4697     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4698                              0, 0, 100, 100, hparent, 0, 0, NULL);
4699     ok (hchild != 0, "Failed to create popup window\n");
4700     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4701     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4702     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4703     flush_sequence();
4704     ShowWindow(hchild, SW_SHOW);
4705     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4706     flush_sequence();
4707     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4708     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4709     flush_sequence();
4710     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4711     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4712     DestroyWindow(hchild);
4713
4714     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4715      * changes nothing in message sequences.
4716      */
4717     flush_sequence();
4718     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4719                              0, 0, 100, 100, hparent, 0, 0, NULL);
4720     ok (hchild != 0, "Failed to create popup window\n");
4721     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4722     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4723     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4724     flush_sequence();
4725     ShowWindow(hchild, SW_SHOW);
4726     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4727     flush_sequence();
4728     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4729     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4730     DestroyWindow(hchild);
4731
4732     flush_sequence();
4733     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4734                            0, 0, 100, 100, hparent, 0, 0, NULL);
4735     ok(hwnd != 0, "Failed to create custom dialog window\n");
4736     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4737
4738     if(0) {
4739     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4740     test_scroll_messages(hwnd);
4741     }
4742
4743     flush_sequence();
4744
4745     test_def_id = 1;
4746     SendMessage(hwnd, WM_NULL, 0, 0);
4747
4748     flush_sequence();
4749     after_end_dialog = 1;
4750     EndDialog( hwnd, 0 );
4751     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4752
4753     DestroyWindow(hwnd);
4754     after_end_dialog = 0;
4755     test_def_id = 0;
4756
4757     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4758                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4759     ok(hwnd != 0, "Failed to create custom dialog window\n");
4760     flush_sequence();
4761     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4762     ShowWindow(hwnd, SW_SHOW);
4763     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4764     DestroyWindow(hwnd);
4765
4766     flush_sequence();
4767     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4768     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4769
4770     DestroyWindow(hparent);
4771     flush_sequence();
4772
4773     /* Message sequence for SetMenu */
4774     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4775     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4776
4777     hmenu = CreateMenu();
4778     ok (hmenu != 0, "Failed to create menu\n");
4779     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4780     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4781                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4782     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4783     ok (SetMenu(hwnd, 0), "SetMenu\n");
4784     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4785     ok (SetMenu(hwnd, 0), "SetMenu\n");
4786     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4787     ShowWindow(hwnd, SW_SHOW);
4788     UpdateWindow( hwnd );
4789     flush_events();
4790     flush_sequence();
4791     ok (SetMenu(hwnd, 0), "SetMenu\n");
4792     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4793     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4794     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4795
4796     UpdateWindow( hwnd );
4797     flush_events();
4798     flush_sequence();
4799     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4800     flush_events();
4801     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4802
4803     DestroyWindow(hwnd);
4804     flush_sequence();
4805
4806     /* Message sequence for EnableWindow */
4807     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4808                               100, 100, 200, 200, 0, 0, 0, NULL);
4809     ok (hparent != 0, "Failed to create parent window\n");
4810     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4811                              0, 0, 10, 10, hparent, 0, 0, NULL);
4812     ok (hchild != 0, "Failed to create child window\n");
4813
4814     SetFocus(hchild);
4815     flush_events();
4816     flush_sequence();
4817
4818     EnableWindow(hparent, FALSE);
4819     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4820
4821     EnableWindow(hparent, TRUE);
4822     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4823
4824     flush_events();
4825     flush_sequence();
4826
4827     test_MsgWaitForMultipleObjects(hparent);
4828
4829     /* the following test causes an exception in user.exe under win9x */
4830     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4831     {
4832         DestroyWindow(hparent);
4833         flush_sequence();
4834         return;
4835     }
4836     PostMessageW( hparent, WM_USER+1, 0, 0 );
4837     /* PeekMessage(NULL) fails, but still removes the message */
4838     SetLastError(0xdeadbeef);
4839     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4840     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4841         GetLastError() == 0xdeadbeef, /* NT4 */
4842         "last error is %d\n", GetLastError() );
4843     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4844     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4845
4846     DestroyWindow(hchild);
4847     DestroyWindow(hparent);
4848     flush_sequence();
4849
4850     /* Message sequences for WM_SETICON */
4851     trace("testing WM_SETICON\n");
4852     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4853                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4854                            NULL, NULL, 0);
4855     ShowWindow(hwnd, SW_SHOW);
4856     UpdateWindow(hwnd);
4857     flush_events();
4858     flush_sequence();
4859     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4860     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4861
4862     ShowWindow(hwnd, SW_HIDE);
4863     flush_events();
4864     flush_sequence();
4865     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4866     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4867     DestroyWindow(hwnd);
4868     flush_sequence();
4869
4870     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4871                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4872                            NULL, NULL, 0);
4873     ShowWindow(hwnd, SW_SHOW);
4874     UpdateWindow(hwnd);
4875     flush_events();
4876     flush_sequence();
4877     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4878     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4879
4880     ShowWindow(hwnd, SW_HIDE);
4881     flush_events();
4882     flush_sequence();
4883     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4884     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4885
4886     flush_sequence();
4887     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4888     if (!res)
4889     {
4890         todo_wine win_skip( "Message 0x3b not supported\n" );
4891         goto done;
4892     }
4893     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4894     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4895     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4896     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4897     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4898     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4899     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4900     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4901
4902     flush_sequence();
4903     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4904     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4905     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4906     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4907     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4908     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4909
4910     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4911     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4912     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4913
4914     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4915     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4916     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4917
4918 done:
4919     DestroyWindow(hwnd);
4920     flush_sequence();
4921 }
4922
4923 static void test_setwindowpos(void)
4924 {
4925     HWND hwnd;
4926     RECT rc;
4927     LRESULT res;
4928     const INT winX = 100;
4929     const INT winY = 100;
4930     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4931
4932     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4933                            0, 0, winX, winY, 0,
4934                            NULL, NULL, 0);
4935
4936     GetWindowRect(hwnd, &rc);
4937     expect(sysX, rc.right);
4938     expect(winY, rc.bottom);
4939
4940     flush_events();
4941     flush_sequence();
4942     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4943     ok_sequence(WmZOrder, "Z-Order", TRUE);
4944     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4945
4946     GetWindowRect(hwnd, &rc);
4947     expect(sysX, rc.right);
4948     expect(winY, rc.bottom);
4949     DestroyWindow(hwnd);
4950 }
4951
4952 static void invisible_parent_tests(void)
4953 {
4954     HWND hparent, hchild;
4955
4956     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4957                               100, 100, 200, 200, 0, 0, 0, NULL);
4958     ok (hparent != 0, "Failed to create parent window\n");
4959     flush_sequence();
4960
4961     /* test showing child with hidden parent */
4962
4963     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4964                              0, 0, 10, 10, hparent, 0, 0, NULL);
4965     ok (hchild != 0, "Failed to create child window\n");
4966     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4967
4968     ShowWindow( hchild, SW_MINIMIZE );
4969     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4970     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4971     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4972
4973     /* repeat */
4974     flush_events();
4975     flush_sequence();
4976     ShowWindow( hchild, SW_MINIMIZE );
4977     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4978
4979     DestroyWindow(hchild);
4980     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4981                              0, 0, 10, 10, hparent, 0, 0, NULL);
4982     flush_sequence();
4983
4984     ShowWindow( hchild, SW_MAXIMIZE );
4985     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4986     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4987     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4988
4989     /* repeat */
4990     flush_events();
4991     flush_sequence();
4992     ShowWindow( hchild, SW_MAXIMIZE );
4993     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4994
4995     DestroyWindow(hchild);
4996     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4997                              0, 0, 10, 10, hparent, 0, 0, NULL);
4998     flush_sequence();
4999
5000     ShowWindow( hchild, SW_RESTORE );
5001     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5002     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5003     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5004
5005     DestroyWindow(hchild);
5006     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5007                              0, 0, 10, 10, hparent, 0, 0, NULL);
5008     flush_sequence();
5009
5010     ShowWindow( hchild, SW_SHOWMINIMIZED );
5011     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5012     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5013     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5014
5015     /* repeat */
5016     flush_events();
5017     flush_sequence();
5018     ShowWindow( hchild, SW_SHOWMINIMIZED );
5019     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5020
5021     DestroyWindow(hchild);
5022     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5023                              0, 0, 10, 10, hparent, 0, 0, NULL);
5024     flush_sequence();
5025
5026     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5027     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5028     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5029     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5030     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5031
5032     DestroyWindow(hchild);
5033     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5034                              0, 0, 10, 10, hparent, 0, 0, NULL);
5035     flush_sequence();
5036
5037     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5038     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5039     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5040     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5041
5042     /* repeat */
5043     flush_events();
5044     flush_sequence();
5045     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5046     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5047
5048     DestroyWindow(hchild);
5049     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5050                              0, 0, 10, 10, hparent, 0, 0, NULL);
5051     flush_sequence();
5052
5053     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5054     ShowWindow( hchild, SW_FORCEMINIMIZE );
5055     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5056 todo_wine {
5057     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5058 }
5059     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5060
5061     DestroyWindow(hchild);
5062     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5063                              0, 0, 10, 10, hparent, 0, 0, NULL);
5064     flush_sequence();
5065
5066     ShowWindow( hchild, SW_SHOWNA );
5067     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5068     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5069     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5070
5071     /* repeat */
5072     flush_events();
5073     flush_sequence();
5074     ShowWindow( hchild, SW_SHOWNA );
5075     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5076
5077     DestroyWindow(hchild);
5078     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5079                              0, 0, 10, 10, hparent, 0, 0, NULL);
5080     flush_sequence();
5081
5082     ShowWindow( hchild, SW_SHOW );
5083     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5084     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5085     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5086
5087     /* repeat */
5088     flush_events();
5089     flush_sequence();
5090     ShowWindow( hchild, SW_SHOW );
5091     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5092
5093     ShowWindow( hchild, SW_HIDE );
5094     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5095     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5096     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5097
5098     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5099     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5100     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5101     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5102
5103     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5104     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5105     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5106     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5107
5108     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5109     flush_sequence();
5110     DestroyWindow(hchild);
5111     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5112
5113     DestroyWindow(hparent);
5114     flush_sequence();
5115 }
5116
5117 /****************** button message test *************************/
5118 #define ID_BUTTON 0x000e
5119
5120 static const struct message WmSetFocusButtonSeq[] =
5121 {
5122     { HCBT_SETFOCUS, hook },
5123     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5124     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5125     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5126     { WM_SETFOCUS, sent|wparam, 0 },
5127     { WM_CTLCOLORBTN, sent|parent },
5128     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5129     { WM_APP, sent|wparam|lparam, 0, 0 },
5130     { 0 }
5131 };
5132 static const struct message WmKillFocusButtonSeq[] =
5133 {
5134     { HCBT_SETFOCUS, hook },
5135     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5136     { WM_KILLFOCUS, sent|wparam, 0 },
5137     { WM_CTLCOLORBTN, sent|parent },
5138     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5139     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5140     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5141     { WM_APP, sent|wparam|lparam, 0, 0 },
5142     { WM_PAINT, sent },
5143     { WM_CTLCOLORBTN, sent|parent },
5144     { 0 }
5145 };
5146 static const struct message WmSetFocusStaticSeq[] =
5147 {
5148     { HCBT_SETFOCUS, hook },
5149     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5150     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5151     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5152     { WM_SETFOCUS, sent|wparam, 0 },
5153     { WM_CTLCOLORSTATIC, sent|parent },
5154     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5155     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5156     { WM_APP, sent|wparam|lparam, 0, 0 },
5157     { 0 }
5158 };
5159 static const struct message WmKillFocusStaticSeq[] =
5160 {
5161     { HCBT_SETFOCUS, hook },
5162     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5163     { WM_KILLFOCUS, sent|wparam, 0 },
5164     { WM_CTLCOLORSTATIC, sent|parent },
5165     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5166     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5167     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5168     { WM_APP, sent|wparam|lparam, 0, 0 },
5169     { WM_PAINT, sent },
5170     { WM_CTLCOLORSTATIC, sent|parent },
5171     { 0 }
5172 };
5173 static const struct message WmSetFocusOwnerdrawSeq[] =
5174 {
5175     { HCBT_SETFOCUS, hook },
5176     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5177     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5178     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5179     { WM_SETFOCUS, sent|wparam, 0 },
5180     { WM_CTLCOLORBTN, sent|parent },
5181     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5182     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5183     { WM_APP, sent|wparam|lparam, 0, 0 },
5184     { 0 }
5185 };
5186 static const struct message WmKillFocusOwnerdrawSeq[] =
5187 {
5188     { HCBT_SETFOCUS, hook },
5189     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5190     { WM_KILLFOCUS, sent|wparam, 0 },
5191     { WM_CTLCOLORBTN, sent|parent },
5192     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5193     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5194     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5195     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5196     { WM_APP, sent|wparam|lparam, 0, 0 },
5197     { WM_PAINT, sent },
5198     { WM_CTLCOLORBTN, sent|parent },
5199     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5200     { 0 }
5201 };
5202 static const struct message WmLButtonDownSeq[] =
5203 {
5204     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5205     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5206     { HCBT_SETFOCUS, hook },
5207     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5208     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5209     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5210     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5211     { WM_CTLCOLORBTN, sent|defwinproc },
5212     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5213     { WM_CTLCOLORBTN, sent|defwinproc },
5214     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5215     { 0 }
5216 };
5217 static const struct message WmLButtonUpSeq[] =
5218 {
5219     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5220     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5221     { WM_CTLCOLORBTN, sent|defwinproc },
5222     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5223     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5224     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5225     { 0 }
5226 };
5227 static const struct message WmSetFontButtonSeq[] =
5228 {
5229     { WM_SETFONT, sent },
5230     { WM_PAINT, sent },
5231     { WM_ERASEBKGND, sent|defwinproc|optional },
5232     { WM_CTLCOLORBTN, sent|defwinproc },
5233     { 0 }
5234 };
5235 static const struct message WmSetStyleButtonSeq[] =
5236 {
5237     { BM_SETSTYLE, sent },
5238     { WM_APP, sent|wparam|lparam, 0, 0 },
5239     { WM_PAINT, sent },
5240     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5241     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5242     { WM_CTLCOLORBTN, sent|parent },
5243     { 0 }
5244 };
5245 static const struct message WmSetStyleStaticSeq[] =
5246 {
5247     { BM_SETSTYLE, sent },
5248     { WM_APP, sent|wparam|lparam, 0, 0 },
5249     { WM_PAINT, sent },
5250     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5251     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5252     { WM_CTLCOLORSTATIC, sent|parent },
5253     { 0 }
5254 };
5255 static const struct message WmSetStyleUserSeq[] =
5256 {
5257     { BM_SETSTYLE, sent },
5258     { WM_APP, sent|wparam|lparam, 0, 0 },
5259     { WM_PAINT, sent },
5260     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5261     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5262     { WM_CTLCOLORBTN, sent|parent },
5263     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5264     { 0 }
5265 };
5266 static const struct message WmSetStyleOwnerdrawSeq[] =
5267 {
5268     { BM_SETSTYLE, sent },
5269     { WM_APP, sent|wparam|lparam, 0, 0 },
5270     { WM_PAINT, sent },
5271     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5272     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5273     { WM_CTLCOLORBTN, sent|parent },
5274     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5275     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5276     { 0 }
5277 };
5278 static const struct message WmSetStateButtonSeq[] =
5279 {
5280     { BM_SETSTATE, sent },
5281     { WM_CTLCOLORBTN, sent|parent },
5282     { WM_APP, sent|wparam|lparam, 0, 0 },
5283     { 0 }
5284 };
5285 static const struct message WmSetStateStaticSeq[] =
5286 {
5287     { BM_SETSTATE, sent },
5288     { WM_CTLCOLORSTATIC, sent|parent },
5289     { WM_APP, sent|wparam|lparam, 0, 0 },
5290     { 0 }
5291 };
5292 static const struct message WmSetStateUserSeq[] =
5293 {
5294     { BM_SETSTATE, sent },
5295     { WM_CTLCOLORBTN, sent|parent },
5296     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5297     { WM_APP, sent|wparam|lparam, 0, 0 },
5298     { 0 }
5299 };
5300 static const struct message WmSetStateOwnerdrawSeq[] =
5301 {
5302     { BM_SETSTATE, sent },
5303     { WM_CTLCOLORBTN, sent|parent },
5304     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5305     { WM_APP, sent|wparam|lparam, 0, 0 },
5306     { 0 }
5307 };
5308 static const struct message WmClearStateButtonSeq[] =
5309 {
5310     { BM_SETSTATE, sent },
5311     { WM_CTLCOLORBTN, sent|parent },
5312     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5313     { WM_APP, sent|wparam|lparam, 0, 0 },
5314     { 0 }
5315 };
5316 static const struct message WmClearStateOwnerdrawSeq[] =
5317 {
5318     { BM_SETSTATE, sent },
5319     { WM_CTLCOLORBTN, sent|parent },
5320     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5321     { WM_APP, sent|wparam|lparam, 0, 0 },
5322     { 0 }
5323 };
5324 static const struct message WmSetCheckIgnoredSeq[] =
5325 {
5326     { BM_SETCHECK, sent },
5327     { WM_APP, sent|wparam|lparam, 0, 0 },
5328     { 0 }
5329 };
5330 static const struct message WmSetCheckStaticSeq[] =
5331 {
5332     { BM_SETCHECK, sent },
5333     { WM_CTLCOLORSTATIC, sent|parent },
5334     { WM_APP, sent|wparam|lparam, 0, 0 },
5335     { 0 }
5336 };
5337
5338 static WNDPROC old_button_proc;
5339
5340 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5341 {
5342     static LONG defwndproc_counter = 0;
5343     LRESULT ret;
5344     struct recvd_message msg;
5345
5346     if (ignore_message( message )) return 0;
5347
5348     switch (message)
5349     {
5350     case WM_SYNCPAINT:
5351         break;
5352     case BM_SETSTATE:
5353         if (GetCapture())
5354             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5355         /* fall through */
5356     default:
5357         msg.hwnd = hwnd;
5358         msg.message = message;
5359         msg.flags = sent|wparam|lparam;
5360         if (defwndproc_counter) msg.flags |= defwinproc;
5361         msg.wParam = wParam;
5362         msg.lParam = lParam;
5363         msg.descr = "button";
5364         add_message(&msg);
5365     }
5366
5367     defwndproc_counter++;
5368     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5369     defwndproc_counter--;
5370
5371     return ret;
5372 }
5373
5374 static void subclass_button(void)
5375 {
5376     WNDCLASSA cls;
5377
5378     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5379
5380     old_button_proc = cls.lpfnWndProc;
5381
5382     cls.hInstance = GetModuleHandle(0);
5383     cls.lpfnWndProc = button_hook_proc;
5384     cls.lpszClassName = "my_button_class";
5385     UnregisterClass(cls.lpszClassName, cls.hInstance);
5386     if (!RegisterClassA(&cls)) assert(0);
5387 }
5388
5389 static void test_button_messages(void)
5390 {
5391     static const struct
5392     {
5393         DWORD style;
5394         DWORD dlg_code;
5395         const struct message *setfocus;
5396         const struct message *killfocus;
5397         const struct message *setstyle;
5398         const struct message *setstate;
5399         const struct message *clearstate;
5400         const struct message *setcheck;
5401     } button[] = {
5402         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5403           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5404           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5405         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5406           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5407           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5408         { BS_CHECKBOX, DLGC_BUTTON,
5409           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5410           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5411         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5412           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5413           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5414         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5415           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5416           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5417         { BS_3STATE, DLGC_BUTTON,
5418           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5419           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5420         { BS_AUTO3STATE, DLGC_BUTTON,
5421           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5422           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5423         { BS_GROUPBOX, DLGC_STATIC,
5424           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5425           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5426         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5427           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5428           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5429         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5430           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5431           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5432         { BS_OWNERDRAW, DLGC_BUTTON,
5433           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5434           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5435     };
5436     unsigned int i;
5437     HWND hwnd, parent;
5438     DWORD dlg_code;
5439     HFONT zfont;
5440
5441     /* selection with VK_SPACE should capture button window */
5442     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5443                            0, 0, 50, 14, 0, 0, 0, NULL);
5444     ok(hwnd != 0, "Failed to create button window\n");
5445     ReleaseCapture();
5446     SetFocus(hwnd);
5447     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5448     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5449     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5450     DestroyWindow(hwnd);
5451
5452     subclass_button();
5453
5454     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5455                              100, 100, 200, 200, 0, 0, 0, NULL);
5456     ok(parent != 0, "Failed to create parent window\n");
5457
5458     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5459     {
5460         MSG msg;
5461         DWORD style, state;
5462
5463         trace("button style %08x\n", button[i].style);
5464
5465         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5466                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5467         ok(hwnd != 0, "Failed to create button window\n");
5468
5469         style = GetWindowLongA(hwnd, GWL_STYLE);
5470         style &= ~(WS_CHILD | BS_NOTIFY);
5471         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5472         if (button[i].style == BS_USERBUTTON)
5473             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5474         else
5475             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5476
5477         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5478         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5479
5480         ShowWindow(hwnd, SW_SHOW);
5481         UpdateWindow(hwnd);
5482         SetFocus(0);
5483         flush_events();
5484         SetFocus(0);
5485         flush_sequence();
5486
5487         log_all_parent_messages++;
5488
5489         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5490         SetFocus(hwnd);
5491         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5492         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5493         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5494
5495         SetFocus(0);
5496         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5497         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5498         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5499
5500         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5501
5502         SendMessage(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5503         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5504         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5505         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5506
5507         style = GetWindowLongA(hwnd, GWL_STYLE);
5508         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5509         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5510         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5511
5512         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5513         ok(state == 0, "expected state 0, got %04x\n", state);
5514
5515         flush_sequence();
5516
5517         SendMessage(hwnd, BM_SETSTATE, TRUE, 0);
5518         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5519         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5520         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5521
5522         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5523         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5524
5525         style = GetWindowLongA(hwnd, GWL_STYLE);
5526         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5527         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5528
5529         flush_sequence();
5530
5531         SendMessage(hwnd, BM_SETSTATE, FALSE, 0);
5532         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5533         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5534         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5535
5536         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5537         ok(state == 0, "expected state 0, got %04x\n", state);
5538
5539         style = GetWindowLongA(hwnd, GWL_STYLE);
5540         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5541         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5542
5543         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5544         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5545
5546         flush_sequence();
5547
5548         SendMessage(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5549         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5550         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5551         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5552
5553         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5554         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5555
5556         style = GetWindowLongA(hwnd, GWL_STYLE);
5557         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5558         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5559
5560         flush_sequence();
5561
5562         SendMessage(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5563         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5564         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5565         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5566
5567         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5568         if (button[i].style == BS_PUSHBUTTON ||
5569             button[i].style == BS_DEFPUSHBUTTON ||
5570             button[i].style == BS_GROUPBOX ||
5571             button[i].style == BS_USERBUTTON ||
5572             button[i].style == BS_OWNERDRAW)
5573             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5574         else
5575             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5576
5577         style = GetWindowLongA(hwnd, GWL_STYLE);
5578         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5579         if (button[i].style == BS_RADIOBUTTON ||
5580             button[i].style == BS_AUTORADIOBUTTON)
5581             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5582         else
5583             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5584
5585         log_all_parent_messages--;
5586
5587         DestroyWindow(hwnd);
5588     }
5589
5590     DestroyWindow(parent);
5591
5592     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5593                            0, 0, 50, 14, 0, 0, 0, NULL);
5594     ok(hwnd != 0, "Failed to create button window\n");
5595
5596     SetForegroundWindow(hwnd);
5597     flush_events();
5598
5599     SetActiveWindow(hwnd);
5600     SetFocus(0);
5601     flush_sequence();
5602
5603     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5604     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5605
5606     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5607     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5608
5609     flush_sequence();
5610     zfont = GetStockObject(SYSTEM_FONT);
5611     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5612     UpdateWindow(hwnd);
5613     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5614
5615     DestroyWindow(hwnd);
5616 }
5617
5618 /****************** static message test *************************/
5619 static const struct message WmSetFontStaticSeq[] =
5620 {
5621     { WM_SETFONT, sent },
5622     { WM_PAINT, sent|defwinproc|optional },
5623     { WM_ERASEBKGND, sent|defwinproc|optional },
5624     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5625     { 0 }
5626 };
5627
5628 static WNDPROC old_static_proc;
5629
5630 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5631 {
5632     static LONG defwndproc_counter = 0;
5633     LRESULT ret;
5634     struct recvd_message msg;
5635
5636     if (ignore_message( message )) return 0;
5637
5638     msg.hwnd = hwnd;
5639     msg.message = message;
5640     msg.flags = sent|wparam|lparam;
5641     if (defwndproc_counter) msg.flags |= defwinproc;
5642     msg.wParam = wParam;
5643     msg.lParam = lParam;
5644     msg.descr = "static";
5645     add_message(&msg);
5646
5647     defwndproc_counter++;
5648     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5649     defwndproc_counter--;
5650
5651     return ret;
5652 }
5653
5654 static void subclass_static(void)
5655 {
5656     WNDCLASSA cls;
5657
5658     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5659
5660     old_static_proc = cls.lpfnWndProc;
5661
5662     cls.hInstance = GetModuleHandle(0);
5663     cls.lpfnWndProc = static_hook_proc;
5664     cls.lpszClassName = "my_static_class";
5665     UnregisterClass(cls.lpszClassName, cls.hInstance);
5666     if (!RegisterClassA(&cls)) assert(0);
5667 }
5668
5669 static void test_static_messages(void)
5670 {
5671     /* FIXME: make as comprehensive as the button message test */
5672     static const struct
5673     {
5674         DWORD style;
5675         DWORD dlg_code;
5676         const struct message *setfont;
5677     } static_ctrl[] = {
5678         { SS_LEFT, DLGC_STATIC,
5679           WmSetFontStaticSeq }
5680     };
5681     unsigned int i;
5682     HWND hwnd;
5683     DWORD dlg_code;
5684
5685     subclass_static();
5686
5687     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5688     {
5689         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5690                                0, 0, 50, 14, 0, 0, 0, NULL);
5691         ok(hwnd != 0, "Failed to create static window\n");
5692
5693         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5694         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5695
5696         ShowWindow(hwnd, SW_SHOW);
5697         UpdateWindow(hwnd);
5698         SetFocus(0);
5699         flush_sequence();
5700
5701         trace("static style %08x\n", static_ctrl[i].style);
5702         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5703         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5704
5705         DestroyWindow(hwnd);
5706     }
5707 }
5708
5709 /****************** ComboBox message test *************************/
5710 #define ID_COMBOBOX 0x000f
5711
5712 static const struct message WmKeyDownComboSeq[] =
5713 {
5714     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5715     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5716     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5717     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5718     { WM_CTLCOLOREDIT, sent|parent },
5719     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5720     { 0 }
5721 };
5722
5723 static const struct message WmSetPosComboSeq[] =
5724 {
5725     { WM_WINDOWPOSCHANGING, sent },
5726     { WM_NCCALCSIZE, sent|wparam, TRUE },
5727     { WM_CHILDACTIVATE, sent },
5728     { WM_WINDOWPOSCHANGED, sent },
5729     { WM_MOVE, sent|defwinproc },
5730     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5731     { WM_WINDOWPOSCHANGING, sent|defwinproc },
5732     { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
5733     { WM_WINDOWPOSCHANGED, sent|defwinproc },
5734     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
5735     { 0 }
5736 };
5737
5738 static WNDPROC old_combobox_proc;
5739
5740 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5741 {
5742     static LONG defwndproc_counter = 0;
5743     LRESULT ret;
5744     struct recvd_message msg;
5745
5746     /* do not log painting messages */
5747     if (message != WM_PAINT &&
5748         message != WM_NCPAINT &&
5749         message != WM_SYNCPAINT &&
5750         message != WM_ERASEBKGND &&
5751         message != WM_NCHITTEST &&
5752         message != WM_GETTEXT &&
5753         !ignore_message( message ))
5754     {
5755         msg.hwnd = hwnd;
5756         msg.message = message;
5757         msg.flags = sent|wparam|lparam;
5758         if (defwndproc_counter) msg.flags |= defwinproc;
5759         msg.wParam = wParam;
5760         msg.lParam = lParam;
5761         msg.descr = "combo";
5762         add_message(&msg);
5763     }
5764
5765     defwndproc_counter++;
5766     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5767     defwndproc_counter--;
5768
5769     return ret;
5770 }
5771
5772 static void subclass_combobox(void)
5773 {
5774     WNDCLASSA cls;
5775
5776     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5777
5778     old_combobox_proc = cls.lpfnWndProc;
5779
5780     cls.hInstance = GetModuleHandle(0);
5781     cls.lpfnWndProc = combobox_hook_proc;
5782     cls.lpszClassName = "my_combobox_class";
5783     UnregisterClass(cls.lpszClassName, cls.hInstance);
5784     if (!RegisterClassA(&cls)) assert(0);
5785 }
5786
5787 static void test_combobox_messages(void)
5788 {
5789     HWND parent, combo;
5790     LRESULT ret;
5791
5792     subclass_combobox();
5793
5794     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5795                              100, 100, 200, 200, 0, 0, 0, NULL);
5796     ok(parent != 0, "Failed to create parent window\n");
5797     flush_sequence();
5798
5799     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5800                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5801     ok(combo != 0, "Failed to create combobox window\n");
5802
5803     UpdateWindow(combo);
5804
5805     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5806     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5807
5808     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5809     ok(ret == 0, "expected 0, got %ld\n", ret);
5810     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5811     ok(ret == 1, "expected 1, got %ld\n", ret);
5812     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5813     ok(ret == 2, "expected 2, got %ld\n", ret);
5814
5815     SendMessage(combo, CB_SETCURSEL, 0, 0);
5816     SetFocus(combo);
5817     flush_sequence();
5818
5819     log_all_parent_messages++;
5820     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5821     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5822     log_all_parent_messages--;
5823     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5824
5825     flush_sequence();
5826     SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
5827     ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
5828
5829     DestroyWindow(combo);
5830     DestroyWindow(parent);
5831 }
5832
5833 /****************** WM_IME_KEYDOWN message test *******************/
5834
5835 static const struct message WmImeKeydownMsgSeq_0[] =
5836 {
5837     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5838     { WM_CHAR, wparam, 'A' },
5839     { 0 }
5840 };
5841
5842 static const struct message WmImeKeydownMsgSeq_1[] =
5843 {
5844     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5845     { WM_CHAR,    optional|wparam, VK_RETURN },
5846     { 0 }
5847 };
5848
5849 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5850 {
5851     struct recvd_message msg;
5852
5853     msg.hwnd = hwnd;
5854     msg.message = message;
5855     msg.flags = wparam|lparam;
5856     msg.wParam = wParam;
5857     msg.lParam = lParam;
5858     msg.descr = "wmime_keydown";
5859     add_message(&msg);
5860
5861     return DefWindowProcA(hwnd, message, wParam, lParam);
5862 }
5863
5864 static void register_wmime_keydown_class(void)
5865 {
5866     WNDCLASSA cls;
5867
5868     ZeroMemory(&cls, sizeof(WNDCLASSA));
5869     cls.lpfnWndProc = wmime_keydown_procA;
5870     cls.hInstance = GetModuleHandleA(0);
5871     cls.lpszClassName = "wmime_keydown_class";
5872     if (!RegisterClassA(&cls)) assert(0);
5873 }
5874
5875 static void test_wmime_keydown_message(void)
5876 {
5877     HWND hwnd;
5878     MSG msg;
5879
5880     trace("Message sequences by WM_IME_KEYDOWN\n");
5881
5882     register_wmime_keydown_class();
5883     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5884                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5885                            NULL, NULL, 0);
5886     flush_events();
5887     flush_sequence();
5888
5889     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5890     SendMessage(hwnd, WM_CHAR, 'A', 1);
5891     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5892
5893     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5894     {
5895         TranslateMessage(&msg);
5896         DispatchMessage(&msg);
5897     }
5898     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5899
5900     DestroyWindow(hwnd);
5901 }
5902
5903 /************* painting message test ********************/
5904
5905 void dump_region(HRGN hrgn)
5906 {
5907     DWORD i, size;
5908     RGNDATA *data = NULL;
5909     RECT *rect;
5910
5911     if (!hrgn)
5912     {
5913         printf( "null region\n" );
5914         return;
5915     }
5916     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5917     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5918     GetRegionData( hrgn, size, data );
5919     printf("%d rects:", data->rdh.nCount );
5920     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5921         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5922     printf("\n");
5923     HeapFree( GetProcessHeap(), 0, data );
5924 }
5925
5926 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5927 {
5928     INT ret;
5929     RECT r1, r2;
5930     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5931     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5932
5933     ret = GetUpdateRgn( hwnd, update, FALSE );
5934     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5935     if (ret == NULLREGION)
5936     {
5937         ok( !hrgn, "Update region shouldn't be empty\n" );
5938     }
5939     else
5940     {
5941         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5942         {
5943             ok( 0, "Regions are different\n" );
5944             if (winetest_debug > 0)
5945             {
5946                 printf( "Update region: " );
5947                 dump_region( update );
5948                 printf( "Wanted region: " );
5949                 dump_region( hrgn );
5950             }
5951         }
5952     }
5953     GetRgnBox( update, &r1 );
5954     GetUpdateRect( hwnd, &r2, FALSE );
5955     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5956         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5957         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5958
5959     DeleteObject( tmp );
5960     DeleteObject( update );
5961 }
5962
5963 static const struct message WmInvalidateRgn[] = {
5964     { WM_NCPAINT, sent },
5965     { WM_GETTEXT, sent|defwinproc|optional },
5966     { 0 }
5967 };
5968
5969 static const struct message WmGetUpdateRect[] = {
5970     { WM_NCPAINT, sent },
5971     { WM_GETTEXT, sent|defwinproc|optional },
5972     { WM_PAINT, sent },
5973     { 0 }
5974 };
5975
5976 static const struct message WmInvalidateFull[] = {
5977     { WM_NCPAINT, sent|wparam, 1 },
5978     { WM_GETTEXT, sent|defwinproc|optional },
5979     { 0 }
5980 };
5981
5982 static const struct message WmInvalidateErase[] = {
5983     { WM_NCPAINT, sent|wparam, 1 },
5984     { WM_GETTEXT, sent|defwinproc|optional },
5985     { WM_ERASEBKGND, sent },
5986     { 0 }
5987 };
5988
5989 static const struct message WmInvalidatePaint[] = {
5990     { WM_PAINT, sent },
5991     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5992     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5993     { 0 }
5994 };
5995
5996 static const struct message WmInvalidateErasePaint[] = {
5997     { WM_PAINT, sent },
5998     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5999     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6000     { WM_ERASEBKGND, sent|beginpaint|optional },
6001     { 0 }
6002 };
6003
6004 static const struct message WmInvalidateErasePaint2[] = {
6005     { WM_PAINT, sent },
6006     { WM_NCPAINT, sent|beginpaint },
6007     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6008     { WM_ERASEBKGND, sent|beginpaint|optional },
6009     { 0 }
6010 };
6011
6012 static const struct message WmErase[] = {
6013     { WM_ERASEBKGND, sent },
6014     { 0 }
6015 };
6016
6017 static const struct message WmPaint[] = {
6018     { WM_PAINT, sent },
6019     { 0 }
6020 };
6021
6022 static const struct message WmParentOnlyPaint[] = {
6023     { WM_PAINT, sent|parent },
6024     { 0 }
6025 };
6026
6027 static const struct message WmInvalidateParent[] = {
6028     { WM_NCPAINT, sent|parent },
6029     { WM_GETTEXT, sent|defwinproc|parent|optional },
6030     { WM_ERASEBKGND, sent|parent },
6031     { 0 }
6032 };
6033
6034 static const struct message WmInvalidateParentChild[] = {
6035     { WM_NCPAINT, sent|parent },
6036     { WM_GETTEXT, sent|defwinproc|parent|optional },
6037     { WM_ERASEBKGND, sent|parent },
6038     { WM_NCPAINT, sent },
6039     { WM_GETTEXT, sent|defwinproc|optional },
6040     { WM_ERASEBKGND, sent },
6041     { 0 }
6042 };
6043
6044 static const struct message WmInvalidateParentChild2[] = {
6045     { WM_ERASEBKGND, sent|parent },
6046     { WM_NCPAINT, sent },
6047     { WM_GETTEXT, sent|defwinproc|optional },
6048     { WM_ERASEBKGND, sent },
6049     { 0 }
6050 };
6051
6052 static const struct message WmParentPaint[] = {
6053     { WM_PAINT, sent|parent },
6054     { WM_PAINT, sent },
6055     { 0 }
6056 };
6057
6058 static const struct message WmParentPaintNc[] = {
6059     { WM_PAINT, sent|parent },
6060     { WM_PAINT, sent },
6061     { WM_NCPAINT, sent|beginpaint },
6062     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6063     { WM_ERASEBKGND, sent|beginpaint|optional },
6064     { 0 }
6065 };
6066
6067 static const struct message WmChildPaintNc[] = {
6068     { WM_PAINT, sent },
6069     { WM_NCPAINT, sent|beginpaint },
6070     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6071     { WM_ERASEBKGND, sent|beginpaint|optional },
6072     { 0 }
6073 };
6074
6075 static const struct message WmParentErasePaint[] = {
6076     { WM_PAINT, sent|parent },
6077     { WM_NCPAINT, sent|parent|beginpaint },
6078     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6079     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6080     { WM_PAINT, sent },
6081     { WM_NCPAINT, sent|beginpaint },
6082     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6083     { WM_ERASEBKGND, sent|beginpaint|optional },
6084     { 0 }
6085 };
6086
6087 static const struct message WmParentOnlyNcPaint[] = {
6088     { WM_PAINT, sent|parent },
6089     { WM_NCPAINT, sent|parent|beginpaint },
6090     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6091     { 0 }
6092 };
6093
6094 static const struct message WmSetParentStyle[] = {
6095     { WM_STYLECHANGING, sent|parent },
6096     { WM_STYLECHANGED, sent|parent },
6097     { 0 }
6098 };
6099
6100 static void test_paint_messages(void)
6101 {
6102     BOOL ret;
6103     RECT rect;
6104     POINT pt;
6105     MSG msg;
6106     HWND hparent, hchild;
6107     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6108     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6109     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6110                                 100, 100, 200, 200, 0, 0, 0, NULL);
6111     ok (hwnd != 0, "Failed to create overlapped window\n");
6112
6113     ShowWindow( hwnd, SW_SHOW );
6114     UpdateWindow( hwnd );
6115     flush_events();
6116     flush_sequence();
6117
6118     check_update_rgn( hwnd, 0 );
6119     SetRectRgn( hrgn, 10, 10, 20, 20 );
6120     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6121     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6122     check_update_rgn( hwnd, hrgn );
6123     SetRectRgn( hrgn2, 20, 20, 30, 30 );
6124     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6125     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6126     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6127     check_update_rgn( hwnd, hrgn );
6128     /* validate everything */
6129     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6130     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6131     check_update_rgn( hwnd, 0 );
6132
6133     /* test empty region */
6134     SetRectRgn( hrgn, 10, 10, 10, 15 );
6135     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6136     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6137     check_update_rgn( hwnd, 0 );
6138     /* test empty rect */
6139     SetRect( &rect, 10, 10, 10, 15 );
6140     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6141     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6142     check_update_rgn( hwnd, 0 );
6143
6144     /* flush pending messages */
6145     flush_events();
6146     flush_sequence();
6147
6148     GetClientRect( hwnd, &rect );
6149     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6150     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6151      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6152      */
6153     trace("testing InvalidateRect(0, NULL, FALSE)\n");
6154     SetRectEmpty( &rect );
6155     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6156     check_update_rgn( hwnd, hrgn );
6157     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6158     flush_events();
6159     ok_sequence( WmPaint, "Paint", FALSE );
6160     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6161     check_update_rgn( hwnd, 0 );
6162
6163     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6164      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6165      */
6166     trace("testing ValidateRect(0, NULL)\n");
6167     SetRectEmpty( &rect );
6168     if (ValidateRect(0, &rect))  /* not supported on Win9x */
6169     {
6170         check_update_rgn( hwnd, hrgn );
6171         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6172         flush_events();
6173         ok_sequence( WmPaint, "Paint", FALSE );
6174         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6175         check_update_rgn( hwnd, 0 );
6176     }
6177
6178     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6179     SetLastError(0xdeadbeef);
6180     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6181     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6182        "wrong error code %d\n", GetLastError());
6183     check_update_rgn( hwnd, 0 );
6184     flush_events();
6185     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6186
6187     trace("testing ValidateRgn(0, NULL)\n");
6188     SetLastError(0xdeadbeef);
6189     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6190     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6191        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6192        "wrong error code %d\n", GetLastError());
6193     check_update_rgn( hwnd, 0 );
6194     flush_events();
6195     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6196
6197     trace("testing UpdateWindow(NULL)\n");
6198     SetLastError(0xdeadbeef);
6199     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6200     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6201        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6202        "wrong error code %d\n", GetLastError());
6203     check_update_rgn( hwnd, 0 );
6204     flush_events();
6205     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6206
6207     /* now with frame */
6208     SetRectRgn( hrgn, -5, -5, 20, 20 );
6209
6210     /* flush pending messages */
6211     flush_events();
6212     flush_sequence();
6213     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6214     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6215
6216     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
6217     check_update_rgn( hwnd, hrgn );
6218
6219     flush_sequence();
6220     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6221     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6222
6223     flush_sequence();
6224     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6225     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6226
6227     GetClientRect( hwnd, &rect );
6228     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6229     check_update_rgn( hwnd, hrgn );
6230
6231     flush_sequence();
6232     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6233     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6234
6235     flush_sequence();
6236     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6237     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6238     check_update_rgn( hwnd, 0 );
6239
6240     flush_sequence();
6241     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6242     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6243     check_update_rgn( hwnd, 0 );
6244
6245     flush_sequence();
6246     SetRectRgn( hrgn, 0, 0, 100, 100 );
6247     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6248     SetRectRgn( hrgn, 0, 0, 50, 100 );
6249     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6250     SetRectRgn( hrgn, 50, 0, 100, 100 );
6251     check_update_rgn( hwnd, hrgn );
6252     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6253     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
6254     check_update_rgn( hwnd, 0 );
6255
6256     flush_sequence();
6257     SetRectRgn( hrgn, 0, 0, 100, 100 );
6258     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6259     SetRectRgn( hrgn, 0, 0, 100, 50 );
6260     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6261     ok_sequence( WmErase, "Erase", FALSE );
6262     SetRectRgn( hrgn, 0, 50, 100, 100 );
6263     check_update_rgn( hwnd, hrgn );
6264
6265     flush_sequence();
6266     SetRectRgn( hrgn, 0, 0, 100, 100 );
6267     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6268     SetRectRgn( hrgn, 0, 0, 50, 50 );
6269     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6270     ok_sequence( WmPaint, "Paint", FALSE );
6271
6272     flush_sequence();
6273     SetRectRgn( hrgn, -4, -4, -2, -2 );
6274     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6275     SetRectRgn( hrgn, -200, -200, -198, -198 );
6276     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6277     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6278
6279     flush_sequence();
6280     SetRectRgn( hrgn, -4, -4, -2, -2 );
6281     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6282     SetRectRgn( hrgn, -4, -4, -3, -3 );
6283     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6284     SetRectRgn( hrgn, 0, 0, 1, 1 );
6285     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6286     ok_sequence( WmPaint, "Paint", FALSE );
6287
6288     flush_sequence();
6289     SetRectRgn( hrgn, -4, -4, -1, -1 );
6290     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6291     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6292     /* make sure no WM_PAINT was generated */
6293     flush_events();
6294     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6295
6296     flush_sequence();
6297     SetRectRgn( hrgn, -4, -4, -1, -1 );
6298     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6299     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6300     {
6301         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6302         {
6303             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6304             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6305             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6306             ret = GetUpdateRect( hwnd, &rect, FALSE );
6307             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6308             /* this will send WM_NCPAINT and validate the non client area */
6309             ret = GetUpdateRect( hwnd, &rect, TRUE );
6310             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6311         }
6312         DispatchMessage( &msg );
6313     }
6314     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6315
6316     DestroyWindow( hwnd );
6317
6318     /* now test with a child window */
6319
6320     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6321                               100, 100, 200, 200, 0, 0, 0, NULL);
6322     ok (hparent != 0, "Failed to create parent window\n");
6323
6324     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6325                            10, 10, 100, 100, hparent, 0, 0, NULL);
6326     ok (hchild != 0, "Failed to create child window\n");
6327
6328     ShowWindow( hparent, SW_SHOW );
6329     UpdateWindow( hparent );
6330     UpdateWindow( hchild );
6331     flush_events();
6332     flush_sequence();
6333     log_all_parent_messages++;
6334
6335     SetRect( &rect, 0, 0, 50, 50 );
6336     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6337     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6338     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6339
6340     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6341     pt.x = pt.y = 0;
6342     MapWindowPoints( hchild, hparent, &pt, 1 );
6343     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6344     check_update_rgn( hchild, hrgn );
6345     SetRectRgn( hrgn, 0, 0, 50, 50 );
6346     check_update_rgn( hparent, hrgn );
6347     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6348     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6349     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6350     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6351
6352     flush_events();
6353     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6354
6355     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6356     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6357     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6358     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6359     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6360
6361     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6362     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6363     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6364
6365     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6366     flush_sequence();
6367     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6368     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6369     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6370
6371     /* flush all paint messages */
6372     flush_events();
6373     flush_sequence();
6374
6375     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6376     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6377     SetRectRgn( hrgn, 0, 0, 50, 50 );
6378     check_update_rgn( hparent, hrgn );
6379     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6380     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6381     SetRectRgn( hrgn, 0, 0, 50, 50 );
6382     check_update_rgn( hparent, hrgn );
6383
6384     /* flush all paint messages */
6385     flush_events();
6386     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6387     flush_sequence();
6388
6389     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6390     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6391     SetRectRgn( hrgn, 0, 0, 50, 50 );
6392     check_update_rgn( hparent, hrgn );
6393     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6394     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6395     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6396     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6397     check_update_rgn( hparent, hrgn );
6398     /* flush all paint messages */
6399     flush_events();
6400     flush_sequence();
6401
6402     /* same as above but parent gets completely validated */
6403     SetRect( &rect, 20, 20, 30, 30 );
6404     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6405     SetRectRgn( hrgn, 20, 20, 30, 30 );
6406     check_update_rgn( hparent, hrgn );
6407     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6408     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6409     check_update_rgn( hparent, 0 );  /* no update region */
6410     flush_events();
6411     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6412
6413     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6414     flush_sequence();
6415     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6416     SetRectRgn( hrgn, 20, 20, 30, 30 );
6417     check_update_rgn( hparent, hrgn );
6418     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6419     SetRectRgn( hrgn, 20, 20, 30, 30 );
6420     check_update_rgn( hparent, hrgn );
6421
6422     /* same as above but normal WM_PAINT doesn't validate parent */
6423     flush_sequence();
6424     SetRect( &rect, 20, 20, 30, 30 );
6425     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6426     SetRectRgn( hrgn, 20, 20, 30, 30 );
6427     check_update_rgn( hparent, hrgn );
6428     /* no WM_PAINT in child while parent still pending */
6429     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6430     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6431     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6432     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6433
6434     flush_sequence();
6435     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6436     /* no WM_PAINT in child while parent still pending */
6437     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6438     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6439     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6440     /* now that parent is valid child should get WM_PAINT */
6441     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6442     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6443     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6444     ok_sequence( WmEmptySeq, "No other message", FALSE );
6445
6446     /* same thing with WS_CLIPCHILDREN in parent */
6447     flush_sequence();
6448     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6449     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6450     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6451     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6452     ok_sequence( WmEmptySeq, "No message", FALSE );
6453     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6454     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6455
6456     flush_sequence();
6457     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6458     SetRectRgn( hrgn, 20, 20, 30, 30 );
6459     check_update_rgn( hparent, hrgn );
6460     /* no WM_PAINT in child while parent still pending */
6461     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6462     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6463     /* WM_PAINT in parent first */
6464     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6465     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6466
6467     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6468     flush_sequence();
6469     SetRect( &rect, 0, 0, 30, 30 );
6470     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6471     SetRectRgn( hrgn, 0, 0, 30, 30 );
6472     check_update_rgn( hparent, hrgn );
6473     flush_events();
6474     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6475
6476     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6477     flush_sequence();
6478     SetRect( &rect, -10, 0, 30, 30 );
6479     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6480     SetRect( &rect, 0, 0, 20, 20 );
6481     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6482     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6483     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6484
6485     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6486     flush_sequence();
6487     SetRect( &rect, -10, 0, 30, 30 );
6488     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6489     SetRect( &rect, 0, 0, 100, 100 );
6490     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6491     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6492     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6493     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6494     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6495
6496     /* test RDW_INTERNALPAINT behavior */
6497
6498     flush_sequence();
6499     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6500     flush_events();
6501     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6502
6503     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6504     flush_events();
6505     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6506
6507     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6508     flush_events();
6509     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6510
6511     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6512     UpdateWindow( hparent );
6513     flush_events();
6514     flush_sequence();
6515     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6516     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6517     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6518                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6519     flush_events();
6520     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6521
6522     UpdateWindow( hparent );
6523     flush_events();
6524     flush_sequence();
6525     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6526     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6527     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6528                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6529     flush_events();
6530     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6531
6532     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6533     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6534     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6535     flush_events();
6536     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6537
6538     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6539     UpdateWindow( hparent );
6540     flush_events();
6541     flush_sequence();
6542     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6543     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6544     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6545                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6546     flush_events();
6547     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6548
6549     UpdateWindow( hparent );
6550     flush_events();
6551     flush_sequence();
6552     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6553     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6554     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6555                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6556     flush_events();
6557     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6558
6559     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6560     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6561
6562     UpdateWindow( hparent );
6563     flush_events();
6564     flush_sequence();
6565     trace("testing SetWindowPos(-10000, -10000) on child\n");
6566     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6567     check_update_rgn( hchild, 0 );
6568     flush_events();
6569
6570 #if 0 /* this one doesn't pass under Wine yet */
6571     UpdateWindow( hparent );
6572     flush_events();
6573     flush_sequence();
6574     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6575     ShowWindow( hchild, SW_MINIMIZE );
6576     check_update_rgn( hchild, 0 );
6577     flush_events();
6578 #endif
6579
6580     UpdateWindow( hparent );
6581     flush_events();
6582     flush_sequence();
6583     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6584     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6585     check_update_rgn( hparent, 0 );
6586     flush_events();
6587
6588     log_all_parent_messages--;
6589     DestroyWindow( hparent );
6590     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6591
6592     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6593
6594     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6595                               100, 100, 200, 200, 0, 0, 0, NULL);
6596     ok (hparent != 0, "Failed to create parent window\n");
6597
6598     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6599                            10, 10, 100, 100, hparent, 0, 0, NULL);
6600     ok (hchild != 0, "Failed to create child window\n");
6601
6602     ShowWindow( hparent, SW_SHOW );
6603     UpdateWindow( hparent );
6604     UpdateWindow( hchild );
6605     flush_events();
6606     flush_sequence();
6607
6608     /* moving child outside of parent boundaries changes update region */
6609     SetRect( &rect, 0, 0, 40, 40 );
6610     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6611     SetRectRgn( hrgn, 0, 0, 40, 40 );
6612     check_update_rgn( hchild, hrgn );
6613     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6614     SetRectRgn( hrgn, 10, 0, 40, 40 );
6615     check_update_rgn( hchild, hrgn );
6616     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6617     SetRectRgn( hrgn, 10, 10, 40, 40 );
6618     check_update_rgn( hchild, hrgn );
6619
6620     /* moving parent off-screen does too */
6621     SetRect( &rect, 0, 0, 100, 100 );
6622     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6623     SetRectRgn( hrgn, 0, 0, 100, 100 );
6624     check_update_rgn( hparent, hrgn );
6625     SetRectRgn( hrgn, 10, 10, 40, 40 );
6626     check_update_rgn( hchild, hrgn );
6627     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6628     SetRectRgn( hrgn, 20, 20, 100, 100 );
6629     check_update_rgn( hparent, hrgn );
6630     SetRectRgn( hrgn, 30, 30, 40, 40 );
6631     check_update_rgn( hchild, hrgn );
6632
6633     /* invalidated region is cropped by the parent rects */
6634     SetRect( &rect, 0, 0, 50, 50 );
6635     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6636     SetRectRgn( hrgn, 30, 30, 50, 50 );
6637     check_update_rgn( hchild, hrgn );
6638
6639     DestroyWindow( hparent );
6640     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6641     flush_sequence();
6642
6643     DeleteObject( hrgn );
6644     DeleteObject( hrgn2 );
6645 }
6646
6647 struct wnd_event
6648 {
6649     HWND hwnd;
6650     HANDLE grand_child;
6651     HANDLE start_event;
6652     HANDLE stop_event;
6653 };
6654
6655 static DWORD WINAPI thread_proc(void *param)
6656 {
6657     MSG msg;
6658     struct wnd_event *wnd_event = param;
6659
6660     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6661                                       100, 100, 200, 200, 0, 0, 0, NULL);
6662     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6663
6664     SetEvent(wnd_event->start_event);
6665
6666     while (GetMessage(&msg, 0, 0, 0))
6667     {
6668         TranslateMessage(&msg);
6669         DispatchMessage(&msg);
6670     }
6671
6672     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6673
6674     return 0;
6675 }
6676
6677 static DWORD CALLBACK create_grand_child_thread( void *param )
6678 {
6679     struct wnd_event *wnd_event = param;
6680     HWND hchild;
6681     MSG msg;
6682
6683     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6684                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6685     ok (hchild != 0, "Failed to create child window\n");
6686     flush_events();
6687     flush_sequence();
6688     SetEvent( wnd_event->start_event );
6689
6690     for (;;)
6691     {
6692         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6693         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6694         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6695     }
6696     return 0;
6697 }
6698
6699 static DWORD CALLBACK create_child_thread( void *param )
6700 {
6701     struct wnd_event *wnd_event = param;
6702     struct wnd_event child_event;
6703     DWORD ret, tid;
6704     MSG msg;
6705
6706     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6707                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6708     ok (child_event.hwnd != 0, "Failed to create child window\n");
6709     SetFocus( child_event.hwnd );
6710     flush_events();
6711     flush_sequence();
6712     child_event.start_event = wnd_event->start_event;
6713     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6714     for (;;)
6715     {
6716         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6717         if (ret != 1) break;
6718         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6719     }
6720     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6721     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6722     return 0;
6723 }
6724
6725 static void test_interthread_messages(void)
6726 {
6727     HANDLE hThread;
6728     DWORD tid;
6729     WNDPROC proc;
6730     MSG msg;
6731     char buf[256];
6732     int len, expected_len;
6733     struct wnd_event wnd_event;
6734     BOOL ret;
6735
6736     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6737     if (!wnd_event.start_event)
6738     {
6739         win_skip("skipping interthread message test under win9x\n");
6740         return;
6741     }
6742
6743     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6744     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6745
6746     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6747
6748     CloseHandle(wnd_event.start_event);
6749
6750     SetLastError(0xdeadbeef);
6751     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
6752     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6753        "wrong error code %d\n", GetLastError());
6754
6755     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6756     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6757
6758     expected_len = lstrlenA("window caption text");
6759     memset(buf, 0, sizeof(buf));
6760     SetLastError(0xdeadbeef);
6761     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6762     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6763     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6764
6765     msg.hwnd = wnd_event.hwnd;
6766     msg.message = WM_GETTEXT;
6767     msg.wParam = sizeof(buf);
6768     msg.lParam = (LPARAM)buf;
6769     memset(buf, 0, sizeof(buf));
6770     SetLastError(0xdeadbeef);
6771     len = DispatchMessageA(&msg);
6772     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6773        "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
6774
6775     /* the following test causes an exception in user.exe under win9x */
6776     msg.hwnd = wnd_event.hwnd;
6777     msg.message = WM_TIMER;
6778     msg.wParam = 0;
6779     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6780     SetLastError(0xdeadbeef);
6781     len = DispatchMessageA(&msg);
6782     ok(!len && GetLastError() == 0xdeadbeef,
6783        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6784
6785     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6786     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6787
6788     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6789     CloseHandle(hThread);
6790
6791     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6792
6793     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6794                               100, 100, 200, 200, 0, 0, 0, NULL);
6795     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6796     flush_sequence();
6797     log_all_parent_messages++;
6798     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6799     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6800     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6801     for (;;)
6802     {
6803         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6804         if (ret != 1) break;
6805         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6806     }
6807     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6808     /* now wait for the thread without processing messages; this shouldn't deadlock */
6809     SetEvent( wnd_event.stop_event );
6810     ret = WaitForSingleObject( hThread, 5000 );
6811     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6812     CloseHandle( hThread );
6813
6814     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6815     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6816     CloseHandle( wnd_event.grand_child );
6817
6818     CloseHandle( wnd_event.start_event );
6819     CloseHandle( wnd_event.stop_event );
6820     flush_events();
6821     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6822     log_all_parent_messages--;
6823     DestroyWindow( wnd_event.hwnd );
6824 }
6825
6826
6827 static const struct message WmVkN[] = {
6828     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6829     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6830     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6831     { WM_CHAR, wparam|lparam, 'n', 1 },
6832     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6833     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6834     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6835     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6836     { 0 }
6837 };
6838 static const struct message WmShiftVkN[] = {
6839     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6840     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6841     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6842     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6843     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6844     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6845     { WM_CHAR, wparam|lparam, 'N', 1 },
6846     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6847     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6848     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6849     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6850     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6851     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6852     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6853     { 0 }
6854 };
6855 static const struct message WmCtrlVkN[] = {
6856     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6857     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6858     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6859     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6860     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6861     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6862     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6863     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6864     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6865     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6866     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6867     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6868     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6869     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6870     { 0 }
6871 };
6872 static const struct message WmCtrlVkN_2[] = {
6873     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6874     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6875     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6876     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6877     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6878     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6879     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6880     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6881     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6882     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6883     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6884     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6885     { 0 }
6886 };
6887 static const struct message WmAltVkN[] = {
6888     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6889     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6890     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6891     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6892     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6893     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6894     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6895     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6896     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6897     { HCBT_SYSCOMMAND, hook },
6898     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6899     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6900     { 0x00AE, sent|defwinproc|optional }, /* XP */
6901     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6902     { WM_INITMENU, sent|defwinproc },
6903     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6904     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6905     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6906     { WM_CAPTURECHANGED, sent|defwinproc },
6907     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6908     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6909     { WM_EXITMENULOOP, sent|defwinproc },
6910     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6911     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6912     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6913     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6914     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6915     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6916     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6917     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6918     { 0 }
6919 };
6920 static const struct message WmAltVkN_2[] = {
6921     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6922     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6923     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6924     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6925     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6926     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6927     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6928     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6929     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6930     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6931     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6932     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6933     { 0 }
6934 };
6935 static const struct message WmCtrlAltVkN[] = {
6936     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6937     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6938     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6939     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6940     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6941     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6942     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6943     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6944     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6945     { WM_CHAR, optional },
6946     { WM_CHAR, sent|optional },
6947     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6948     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6949     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6950     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6951     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6952     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6953     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6954     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6955     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6956     { 0 }
6957 };
6958 static const struct message WmCtrlShiftVkN[] = {
6959     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6960     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6961     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6962     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6963     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6964     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6965     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6966     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6967     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6968     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6969     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6970     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6971     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6972     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6973     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6974     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6975     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6976     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6977     { 0 }
6978 };
6979 static const struct message WmCtrlAltShiftVkN[] = {
6980     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6981     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6982     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6983     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6984     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6985     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6986     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6987     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6988     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6989     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6990     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6991     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6992     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6993     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6994     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6995     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6996     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6997     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6998     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6999     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7000     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7001     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
7002     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
7003     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
7004     { 0 }
7005 };
7006 static const struct message WmAltPressRelease[] = {
7007     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
7008     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
7009     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
7010     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7011     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7012     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7013     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
7014     { HCBT_SYSCOMMAND, hook },
7015     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7016     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7017     { WM_INITMENU, sent|defwinproc },
7018     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7019     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7020     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7021
7022     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
7023
7024     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7025     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7026     { WM_CAPTURECHANGED, sent|defwinproc },
7027     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7028     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7029     { WM_EXITMENULOOP, sent|defwinproc },
7030     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7031     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7032     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7033     { 0 }
7034 };
7035 static const struct message WmShiftMouseButton[] = {
7036     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7037     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7038     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7039     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7040     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7041     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7042     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7043     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7044     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7045     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7046     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7047     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7048     { 0 }
7049 };
7050 static const struct message WmF1Seq[] = {
7051     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7052     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7053     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7054     { WM_KEYF1, wparam|lparam, 0, 0 },
7055     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7056     { WM_HELP, sent|defwinproc },
7057     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7058     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7059     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7060     { 0 }
7061 };
7062 static const struct message WmVkAppsSeq[] = {
7063     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7064     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7065     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7066     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7067     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7068     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7069     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7070     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7071     { 0 }
7072 };
7073 static const struct message WmVkF10Seq[] = {
7074     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7075     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7076     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7077     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7078     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7079     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7080     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7081     { HCBT_SYSCOMMAND, hook },
7082     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7083     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7084     { WM_INITMENU, sent|defwinproc },
7085     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7086     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7087     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7088
7089     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7090
7091     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7092     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7093     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7094     { WM_CAPTURECHANGED, sent|defwinproc },
7095     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7096     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7097     { WM_EXITMENULOOP, sent|defwinproc },
7098     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7099     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7100     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7101     { 0 }
7102 };
7103 static const struct message WmShiftF10Seq[] = {
7104     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7105     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7106     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7107     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7108     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7109     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7110     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7111     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7112     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7113     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7114     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7115     { HCBT_SYSCOMMAND, hook },
7116     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7117     { WM_INITMENU, sent|defwinproc },
7118     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7119     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7120     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7121     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7122     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7123     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7124     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7125     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7126     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7127     { 0 }
7128 };
7129
7130 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7131 {
7132     MSG msg;
7133
7134     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7135     {
7136         struct recvd_message log_msg;
7137
7138         /* ignore some unwanted messages */
7139         if (msg.message == WM_MOUSEMOVE ||
7140             msg.message == WM_TIMER ||
7141             ignore_message( msg.message ))
7142             continue;
7143
7144         log_msg.hwnd = msg.hwnd;
7145         log_msg.message = msg.message;
7146         log_msg.flags = wparam|lparam;
7147         log_msg.wParam = msg.wParam;
7148         log_msg.lParam = msg.lParam;
7149         log_msg.descr = "accel";
7150         add_message(&log_msg);
7151
7152         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
7153         {
7154             TranslateMessage(&msg);
7155             DispatchMessage(&msg);
7156         }
7157     }
7158 }
7159
7160 static void test_accelerators(void)
7161 {
7162     RECT rc;
7163     POINT pt;
7164     SHORT state;
7165     HACCEL hAccel;
7166     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7167                                 100, 100, 200, 200, 0, 0, 0, NULL);
7168     BOOL ret;
7169
7170     assert(hwnd != 0);
7171     UpdateWindow(hwnd);
7172     flush_events();
7173     flush_sequence();
7174
7175     SetFocus(hwnd);
7176     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7177
7178     state = GetKeyState(VK_SHIFT);
7179     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7180     state = GetKeyState(VK_CAPITAL);
7181     ok(state == 0, "wrong CapsLock state %04x\n", state);
7182
7183     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
7184     assert(hAccel != 0);
7185
7186     flush_events();
7187     pump_msg_loop(hwnd, 0);
7188     flush_sequence();
7189
7190     trace("testing VK_N press/release\n");
7191     flush_sequence();
7192     keybd_event('N', 0, 0, 0);
7193     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7194     pump_msg_loop(hwnd, hAccel);
7195     if (!sequence_cnt)  /* we didn't get any message */
7196     {
7197         skip( "queuing key events not supported\n" );
7198         goto done;
7199     }
7200     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7201
7202     trace("testing Shift+VK_N press/release\n");
7203     flush_sequence();
7204     keybd_event(VK_SHIFT, 0, 0, 0);
7205     keybd_event('N', 0, 0, 0);
7206     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7207     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7208     pump_msg_loop(hwnd, hAccel);
7209     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7210
7211     trace("testing Ctrl+VK_N press/release\n");
7212     flush_sequence();
7213     keybd_event(VK_CONTROL, 0, 0, 0);
7214     keybd_event('N', 0, 0, 0);
7215     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7216     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7217     pump_msg_loop(hwnd, hAccel);
7218     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7219
7220     trace("testing Alt+VK_N press/release\n");
7221     flush_sequence();
7222     keybd_event(VK_MENU, 0, 0, 0);
7223     keybd_event('N', 0, 0, 0);
7224     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7225     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7226     pump_msg_loop(hwnd, hAccel);
7227     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7228
7229     trace("testing Ctrl+Alt+VK_N press/release 1\n");
7230     flush_sequence();
7231     keybd_event(VK_CONTROL, 0, 0, 0);
7232     keybd_event(VK_MENU, 0, 0, 0);
7233     keybd_event('N', 0, 0, 0);
7234     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7235     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7236     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7237     pump_msg_loop(hwnd, hAccel);
7238     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7239
7240     ret = DestroyAcceleratorTable(hAccel);
7241     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7242
7243     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
7244     assert(hAccel != 0);
7245
7246     trace("testing VK_N press/release\n");
7247     flush_sequence();
7248     keybd_event('N', 0, 0, 0);
7249     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7250     pump_msg_loop(hwnd, hAccel);
7251     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7252
7253     trace("testing Shift+VK_N press/release\n");
7254     flush_sequence();
7255     keybd_event(VK_SHIFT, 0, 0, 0);
7256     keybd_event('N', 0, 0, 0);
7257     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7258     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7259     pump_msg_loop(hwnd, hAccel);
7260     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7261
7262     trace("testing Ctrl+VK_N press/release 2\n");
7263     flush_sequence();
7264     keybd_event(VK_CONTROL, 0, 0, 0);
7265     keybd_event('N', 0, 0, 0);
7266     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7267     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7268     pump_msg_loop(hwnd, hAccel);
7269     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7270
7271     trace("testing Alt+VK_N press/release 2\n");
7272     flush_sequence();
7273     keybd_event(VK_MENU, 0, 0, 0);
7274     keybd_event('N', 0, 0, 0);
7275     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7276     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7277     pump_msg_loop(hwnd, hAccel);
7278     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7279
7280     trace("testing Ctrl+Alt+VK_N press/release 2\n");
7281     flush_sequence();
7282     keybd_event(VK_CONTROL, 0, 0, 0);
7283     keybd_event(VK_MENU, 0, 0, 0);
7284     keybd_event('N', 0, 0, 0);
7285     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7286     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7287     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7288     pump_msg_loop(hwnd, hAccel);
7289     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7290
7291     trace("testing Ctrl+Shift+VK_N press/release\n");
7292     flush_sequence();
7293     keybd_event(VK_CONTROL, 0, 0, 0);
7294     keybd_event(VK_SHIFT, 0, 0, 0);
7295     keybd_event('N', 0, 0, 0);
7296     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7297     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7298     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7299     pump_msg_loop(hwnd, hAccel);
7300     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7301
7302     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7303     flush_sequence();
7304     keybd_event(VK_CONTROL, 0, 0, 0);
7305     keybd_event(VK_MENU, 0, 0, 0);
7306     keybd_event(VK_SHIFT, 0, 0, 0);
7307     keybd_event('N', 0, 0, 0);
7308     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7309     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7310     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7311     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7312     pump_msg_loop(hwnd, hAccel);
7313     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7314
7315     ret = DestroyAcceleratorTable(hAccel);
7316     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7317     hAccel = 0;
7318
7319     trace("testing Alt press/release\n");
7320     flush_sequence();
7321     keybd_event(VK_MENU, 0, 0, 0);
7322     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7323     keybd_event(VK_MENU, 0, 0, 0);
7324     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7325     pump_msg_loop(hwnd, 0);
7326     /* this test doesn't pass in Wine for managed windows */
7327     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7328
7329     trace("testing VK_F1 press/release\n");
7330     keybd_event(VK_F1, 0, 0, 0);
7331     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7332     pump_msg_loop(hwnd, 0);
7333     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7334
7335     trace("testing VK_APPS press/release\n");
7336     keybd_event(VK_APPS, 0, 0, 0);
7337     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7338     pump_msg_loop(hwnd, 0);
7339     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7340
7341     trace("testing VK_F10 press/release\n");
7342     keybd_event(VK_F10, 0, 0, 0);
7343     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7344     keybd_event(VK_F10, 0, 0, 0);
7345     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7346     pump_msg_loop(hwnd, 0);
7347     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7348
7349     trace("testing SHIFT+F10 press/release\n");
7350     keybd_event(VK_SHIFT, 0, 0, 0);
7351     keybd_event(VK_F10, 0, 0, 0);
7352     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7353     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7354     keybd_event(VK_ESCAPE, 0, 0, 0);
7355     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7356     pump_msg_loop(hwnd, 0);
7357     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7358
7359     trace("testing Shift+MouseButton press/release\n");
7360     /* first, move mouse pointer inside of the window client area */
7361     GetClientRect(hwnd, &rc);
7362     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7363     rc.left += (rc.right - rc.left)/2;
7364     rc.top += (rc.bottom - rc.top)/2;
7365     SetCursorPos(rc.left, rc.top);
7366     SetActiveWindow(hwnd);
7367
7368     flush_events();
7369     flush_sequence();
7370     GetCursorPos(&pt);
7371     if (pt.x == rc.left && pt.y == rc.top)
7372     {
7373         int i;
7374         keybd_event(VK_SHIFT, 0, 0, 0);
7375         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7376         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7377         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7378         pump_msg_loop(hwnd, 0);
7379         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7380         if (i < sequence_cnt)
7381             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7382         else
7383             skip( "Shift+MouseButton event didn't get to the window\n" );
7384     }
7385
7386 done:
7387     if (hAccel) DestroyAcceleratorTable(hAccel);
7388     DestroyWindow(hwnd);
7389 }
7390
7391 /************* window procedures ********************/
7392
7393 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
7394                              WPARAM wParam, LPARAM lParam)
7395 {
7396     static LONG defwndproc_counter = 0;
7397     static LONG beginpaint_counter = 0;
7398     LRESULT ret;
7399     struct recvd_message msg;
7400
7401     if (ignore_message( message )) return 0;
7402
7403     switch (message)
7404     {
7405         case WM_ENABLE:
7406         {
7407             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7408             ok((BOOL)wParam == !(style & WS_DISABLED),
7409                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7410             break;
7411         }
7412
7413         case WM_CAPTURECHANGED:
7414             if (test_DestroyWindow_flag)
7415             {
7416                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7417                 if (style & WS_CHILD)
7418                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7419                 else if (style & WS_POPUP)
7420                     lParam = WND_POPUP_ID;
7421                 else
7422                     lParam = WND_PARENT_ID;
7423             }
7424             break;
7425
7426         case WM_NCDESTROY:
7427         {
7428             HWND capture;
7429
7430             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7431             capture = GetCapture();
7432             if (capture)
7433             {
7434                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7435                 trace("current capture %p, releasing...\n", capture);
7436                 ReleaseCapture();
7437             }
7438         }
7439         /* fall through */
7440         case WM_DESTROY:
7441             if (pGetAncestor)
7442                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7443             if (test_DestroyWindow_flag)
7444             {
7445                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7446                 if (style & WS_CHILD)
7447                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7448                 else if (style & WS_POPUP)
7449                     lParam = WND_POPUP_ID;
7450                 else
7451                     lParam = WND_PARENT_ID;
7452             }
7453             break;
7454
7455         /* test_accelerators() depends on this */
7456         case WM_NCHITTEST:
7457             return HTCLIENT;
7458
7459         /* ignore */
7460         case WM_MOUSEMOVE:
7461         case WM_MOUSEACTIVATE:
7462         case WM_NCMOUSEMOVE:
7463         case WM_SETCURSOR:
7464         case WM_IME_SELECT:
7465             return 0;
7466     }
7467
7468     msg.hwnd = hwnd;
7469     msg.message = message;
7470     msg.flags = sent|wparam|lparam;
7471     if (defwndproc_counter) msg.flags |= defwinproc;
7472     if (beginpaint_counter) msg.flags |= beginpaint;
7473     msg.wParam = wParam;
7474     msg.lParam = lParam;
7475     msg.descr = "MsgCheckProc";
7476     add_message(&msg);
7477
7478     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7479     {
7480         HWND parent = GetParent(hwnd);
7481         RECT rc;
7482         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7483
7484         GetClientRect(parent, &rc);
7485         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7486         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7487               minmax->ptReserved.x, minmax->ptReserved.y,
7488               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7489               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7490               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7491               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7492
7493         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7494            minmax->ptMaxSize.x, rc.right);
7495         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7496            minmax->ptMaxSize.y, rc.bottom);
7497     }
7498
7499     if (message == WM_PAINT)
7500     {
7501         PAINTSTRUCT ps;
7502         beginpaint_counter++;
7503         BeginPaint( hwnd, &ps );
7504         beginpaint_counter--;
7505         EndPaint( hwnd, &ps );
7506         return 0;
7507     }
7508
7509     defwndproc_counter++;
7510     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7511                   : DefWindowProcA(hwnd, message, wParam, lParam);
7512     defwndproc_counter--;
7513
7514     return ret;
7515 }
7516
7517 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7518 {
7519     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7520 }
7521
7522 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7523 {
7524     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7525 }
7526
7527 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7528 {
7529     static LONG defwndproc_counter = 0;
7530     LRESULT ret;
7531     struct recvd_message msg;
7532
7533     if (ignore_message( message )) return 0;
7534
7535     switch (message)
7536     {
7537     case WM_QUERYENDSESSION:
7538     case WM_ENDSESSION:
7539         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7540         break;
7541     }
7542
7543     msg.hwnd = hwnd;
7544     msg.message = message;
7545     msg.flags = sent|wparam|lparam;
7546     if (defwndproc_counter) msg.flags |= defwinproc;
7547     msg.wParam = wParam;
7548     msg.lParam = lParam;
7549     msg.descr = "popup";
7550     add_message(&msg);
7551
7552     if (message == WM_CREATE)
7553     {
7554         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7555         SetWindowLongA(hwnd, GWL_STYLE, style);
7556     }
7557
7558     defwndproc_counter++;
7559     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7560     defwndproc_counter--;
7561
7562     return ret;
7563 }
7564
7565 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7566 {
7567     static LONG defwndproc_counter = 0;
7568     static LONG beginpaint_counter = 0;
7569     LRESULT ret;
7570     struct recvd_message msg;
7571
7572     if (ignore_message( message )) return 0;
7573
7574     if (log_all_parent_messages ||
7575         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7576         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7577         message == WM_ENABLE || message == WM_ENTERIDLE ||
7578         message == WM_DRAWITEM || message == WM_COMMAND ||
7579         message == WM_IME_SETCONTEXT)
7580     {
7581         switch (message)
7582         {
7583             /* ignore */
7584             case WM_NCHITTEST:
7585                 return HTCLIENT;
7586             case WM_SETCURSOR:
7587             case WM_MOUSEMOVE:
7588             case WM_NCMOUSEMOVE:
7589                 return 0;
7590
7591             case WM_ERASEBKGND:
7592             {
7593                 RECT rc;
7594                 INT ret = GetClipBox((HDC)wParam, &rc);
7595
7596                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7597                        ret, rc.left, rc.top, rc.right, rc.bottom);
7598                 break;
7599             }
7600         }
7601
7602         msg.hwnd = hwnd;
7603         msg.message = message;
7604         msg.flags = sent|parent|wparam|lparam;
7605         if (defwndproc_counter) msg.flags |= defwinproc;
7606         if (beginpaint_counter) msg.flags |= beginpaint;
7607         msg.wParam = wParam;
7608         msg.lParam = lParam;
7609         msg.descr = "parent";
7610         add_message(&msg);
7611     }
7612
7613     if (message == WM_PAINT)
7614     {
7615         PAINTSTRUCT ps;
7616         beginpaint_counter++;
7617         BeginPaint( hwnd, &ps );
7618         beginpaint_counter--;
7619         EndPaint( hwnd, &ps );
7620         return 0;
7621     }
7622
7623     defwndproc_counter++;
7624     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7625     defwndproc_counter--;
7626
7627     return ret;
7628 }
7629
7630 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
7631 {
7632     if (message == WM_CREATE)
7633         PostMessage(hwnd, WM_CLOSE, 0, 0);
7634     else if (message == WM_CLOSE)
7635     {
7636         /* Only the first WM_QUIT will survive the window destruction */
7637         PostMessage(hwnd, WM_USER, 0x1234, 0x5678);
7638         PostMessage(hwnd, WM_QUIT, 0x1234, 0x5678);
7639         PostMessage(hwnd, WM_QUIT, 0x4321, 0x8765);
7640     }
7641
7642     return DefWindowProcA(hwnd, message, wp, lp);
7643 }
7644
7645 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7646 {
7647     static LONG defwndproc_counter = 0;
7648     LRESULT ret;
7649     struct recvd_message msg;
7650
7651     if (ignore_message( message )) return 0;
7652
7653     if (test_def_id)
7654     {
7655         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7656         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7657         if (after_end_dialog)
7658             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7659         else
7660             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7661     }
7662
7663     msg.hwnd = hwnd;
7664     msg.message = message;
7665     msg.flags = sent|wparam|lparam;
7666     if (defwndproc_counter) msg.flags |= defwinproc;
7667     msg.wParam = wParam;
7668     msg.lParam = lParam;
7669     msg.descr = "dialog";
7670     add_message(&msg);
7671
7672     defwndproc_counter++;
7673     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7674     defwndproc_counter--;
7675
7676     return ret;
7677 }
7678
7679 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7680 {
7681     static LONG defwndproc_counter = 0;
7682     LRESULT ret;
7683     struct recvd_message msg;
7684
7685     /* log only specific messages we are interested in */
7686     switch (message)
7687     {
7688 #if 0 /* probably log these as well */
7689     case WM_ACTIVATE:
7690     case WM_SETFOCUS:
7691     case WM_KILLFOCUS:
7692 #endif
7693     case WM_SHOWWINDOW:
7694     case WM_SIZE:
7695     case WM_MOVE:
7696     case WM_GETMINMAXINFO:
7697     case WM_WINDOWPOSCHANGING:
7698     case WM_WINDOWPOSCHANGED:
7699         break;
7700
7701     default: /* ignore */
7702         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7703         return DefWindowProcA(hwnd, message, wParam, lParam);
7704     }
7705
7706     msg.hwnd = hwnd;
7707     msg.message = message;
7708     msg.flags = sent|wparam|lparam;
7709     if (defwndproc_counter) msg.flags |= defwinproc;
7710     msg.wParam = wParam;
7711     msg.lParam = lParam;
7712     msg.descr = "show";
7713     add_message(&msg);
7714
7715     defwndproc_counter++;
7716     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7717     defwndproc_counter--;
7718
7719     return ret;
7720 }
7721
7722 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7723 {
7724     switch (msg)
7725     {
7726         case WM_CREATE: return 0;
7727         case WM_PAINT:
7728         {
7729             MSG msg2;
7730             static int i = 0;
7731
7732             if (i < 256)
7733             {
7734                 i++;
7735                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7736                 {
7737                     TranslateMessage(&msg2);
7738                     DispatchMessage(&msg2);
7739                 }
7740                 i--;
7741             }
7742             else ok(broken(1), "infinite loop\n");
7743             if ( i == 0)
7744                 paint_loop_done = 1;
7745             return DefWindowProcA(hWnd,msg,wParam,lParam);
7746         }
7747     }
7748     return DefWindowProcA(hWnd,msg,wParam,lParam);
7749 }
7750
7751 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7752 {
7753     static LONG defwndproc_counter = 0;
7754     LRESULT ret;
7755     struct recvd_message msg;
7756     DWORD queue_status;
7757
7758     if (ignore_message( message )) return 0;
7759
7760     if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
7761         message == WM_HOTKEY || message >= WM_APP)
7762     {
7763         msg.hwnd = hwnd;
7764         msg.message = message;
7765         msg.flags = sent|wparam|lparam;
7766         if (defwndproc_counter) msg.flags |= defwinproc;
7767         msg.wParam = wParam;
7768         msg.lParam = lParam;
7769         msg.descr = "HotkeyMsgCheckProcA";
7770         add_message(&msg);
7771     }
7772
7773     defwndproc_counter++;
7774     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7775     defwndproc_counter--;
7776
7777     if (message == WM_APP)
7778     {
7779         queue_status = GetQueueStatus(QS_HOTKEY);
7780         ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
7781         queue_status = GetQueueStatus(QS_POSTMESSAGE);
7782         ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
7783         PostMessageA(hwnd, WM_APP+1, 0, 0);
7784     }
7785     else if (message == WM_APP+1)
7786     {
7787         queue_status = GetQueueStatus(QS_HOTKEY);
7788         ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
7789     }
7790
7791     return ret;
7792 }
7793
7794 static BOOL RegisterWindowClasses(void)
7795 {
7796     WNDCLASSA cls;
7797     WNDCLASSW clsW;
7798
7799     cls.style = 0;
7800     cls.lpfnWndProc = MsgCheckProcA;
7801     cls.cbClsExtra = 0;
7802     cls.cbWndExtra = 0;
7803     cls.hInstance = GetModuleHandleA(0);
7804     cls.hIcon = 0;
7805     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7806     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7807     cls.lpszMenuName = NULL;
7808     cls.lpszClassName = "TestWindowClass";
7809     if(!RegisterClassA(&cls)) return FALSE;
7810
7811     cls.lpfnWndProc = HotkeyMsgCheckProcA;
7812     cls.lpszClassName = "HotkeyWindowClass";
7813     if(!RegisterClassA(&cls)) return FALSE;
7814
7815     cls.lpfnWndProc = ShowWindowProcA;
7816     cls.lpszClassName = "ShowWindowClass";
7817     if(!RegisterClassA(&cls)) return FALSE;
7818
7819     cls.lpfnWndProc = PopupMsgCheckProcA;
7820     cls.lpszClassName = "TestPopupClass";
7821     if(!RegisterClassA(&cls)) return FALSE;
7822
7823     cls.lpfnWndProc = ParentMsgCheckProcA;
7824     cls.lpszClassName = "TestParentClass";
7825     if(!RegisterClassA(&cls)) return FALSE;
7826
7827     cls.lpfnWndProc = StopQuitMsgCheckProcA;
7828     cls.lpszClassName = "StopQuitClass";
7829     if(!RegisterClassA(&cls)) return FALSE;
7830
7831     cls.lpfnWndProc = DefWindowProcA;
7832     cls.lpszClassName = "SimpleWindowClass";
7833     if(!RegisterClassA(&cls)) return FALSE;
7834
7835     cls.lpfnWndProc = PaintLoopProcA;
7836     cls.lpszClassName = "PaintLoopWindowClass";
7837     if(!RegisterClassA(&cls)) return FALSE;
7838
7839     cls.style = CS_NOCLOSE;
7840     cls.lpszClassName = "NoCloseWindowClass";
7841     if(!RegisterClassA(&cls)) return FALSE;
7842
7843     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7844     cls.style = 0;
7845     cls.hInstance = GetModuleHandleA(0);
7846     cls.hbrBackground = 0;
7847     cls.lpfnWndProc = TestDlgProcA;
7848     cls.lpszClassName = "TestDialogClass";
7849     if(!RegisterClassA(&cls)) return FALSE;
7850
7851     clsW.style = 0;
7852     clsW.lpfnWndProc = MsgCheckProcW;
7853     clsW.cbClsExtra = 0;
7854     clsW.cbWndExtra = 0;
7855     clsW.hInstance = GetModuleHandleW(0);
7856     clsW.hIcon = 0;
7857     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7858     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7859     clsW.lpszMenuName = NULL;
7860     clsW.lpszClassName = testWindowClassW;
7861     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7862
7863     return TRUE;
7864 }
7865
7866 static BOOL is_our_logged_class(HWND hwnd)
7867 {
7868     char buf[256];
7869
7870     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7871     {
7872         if (!lstrcmpiA(buf, "TestWindowClass") ||
7873             !lstrcmpiA(buf, "ShowWindowClass") ||
7874             !lstrcmpiA(buf, "TestParentClass") ||
7875             !lstrcmpiA(buf, "TestPopupClass") ||
7876             !lstrcmpiA(buf, "SimpleWindowClass") ||
7877             !lstrcmpiA(buf, "TestDialogClass") ||
7878             !lstrcmpiA(buf, "MDI_frame_class") ||
7879             !lstrcmpiA(buf, "MDI_client_class") ||
7880             !lstrcmpiA(buf, "MDI_child_class") ||
7881             !lstrcmpiA(buf, "my_button_class") ||
7882             !lstrcmpiA(buf, "my_edit_class") ||
7883             !lstrcmpiA(buf, "static") ||
7884             !lstrcmpiA(buf, "ListBox") ||
7885             !lstrcmpiA(buf, "ComboBox") ||
7886             !lstrcmpiA(buf, "MyDialogClass") ||
7887             !lstrcmpiA(buf, "#32770") ||
7888             !lstrcmpiA(buf, "#32768"))
7889         return TRUE;
7890     }
7891     return FALSE;
7892 }
7893
7894 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7895
7896     HWND hwnd;
7897
7898     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7899
7900     if (nCode == HCBT_CLICKSKIPPED)
7901     {
7902         /* ignore this event, XP sends it a lot when switching focus between windows */
7903         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7904     }
7905
7906     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7907     {
7908         struct recvd_message msg;
7909
7910         msg.hwnd = 0;
7911         msg.message = nCode;
7912         msg.flags = hook|wparam|lparam;
7913         msg.wParam = wParam;
7914         msg.lParam = lParam;
7915         msg.descr = "CBT";
7916         add_message(&msg);
7917
7918         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7919     }
7920
7921     if (nCode == HCBT_DESTROYWND)
7922     {
7923         if (test_DestroyWindow_flag)
7924         {
7925             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7926             if (style & WS_CHILD)
7927                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7928             else if (style & WS_POPUP)
7929                 lParam = WND_POPUP_ID;
7930             else
7931                 lParam = WND_PARENT_ID;
7932         }
7933     }
7934
7935     /* Log also SetFocus(0) calls */
7936     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7937
7938     if (is_our_logged_class(hwnd))
7939     {
7940         struct recvd_message msg;
7941
7942         msg.hwnd = hwnd;
7943         msg.message = nCode;
7944         msg.flags = hook|wparam|lparam;
7945         msg.wParam = wParam;
7946         msg.lParam = lParam;
7947         msg.descr = "CBT";
7948         add_message(&msg);
7949     }
7950     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7951 }
7952
7953 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7954                                     DWORD event,
7955                                     HWND hwnd,
7956                                     LONG object_id,
7957                                     LONG child_id,
7958                                     DWORD thread_id,
7959                                     DWORD event_time)
7960 {
7961     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7962
7963     /* ignore mouse cursor events */
7964     if (object_id == OBJID_CURSOR) return;
7965
7966     if (!hwnd || is_our_logged_class(hwnd))
7967     {
7968         struct recvd_message msg;
7969
7970         msg.hwnd = hwnd;
7971         msg.message = event;
7972         msg.flags = winevent_hook|wparam|lparam;
7973         msg.wParam = object_id;
7974         msg.lParam = child_id;
7975         msg.descr = "WEH";
7976         add_message(&msg);
7977     }
7978 }
7979
7980 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7981 static const WCHAR wszAnsi[] = {'U',0};
7982
7983 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7984 {
7985     switch (uMsg)
7986     {
7987     case CB_FINDSTRINGEXACT:
7988         trace("String: %p\n", (LPCWSTR)lParam);
7989         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7990             return 1;
7991         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7992             return 0;
7993         return -1;
7994     }
7995     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7996 }
7997
7998 static const struct message WmGetTextLengthAfromW[] = {
7999     { WM_GETTEXTLENGTH, sent },
8000     { WM_GETTEXT, sent|optional },
8001     { 0 }
8002 };
8003
8004 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
8005
8006 /* dummy window proc for WM_GETTEXTLENGTH test */
8007 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
8008 {
8009     switch(msg)
8010     {
8011     case WM_GETTEXTLENGTH:
8012         return lstrlenW(dummy_window_text) + 37;  /* some random length */
8013     case WM_GETTEXT:
8014         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
8015         return lstrlenW( (LPWSTR)lp );
8016     default:
8017         return DefWindowProcW( hwnd, msg, wp, lp );
8018     }
8019 }
8020
8021 static void test_message_conversion(void)
8022 {
8023     static const WCHAR wszMsgConversionClass[] =
8024         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
8025     WNDCLASSW cls;
8026     LRESULT lRes;
8027     HWND hwnd;
8028     WNDPROC wndproc, newproc;
8029     BOOL ret;
8030
8031     cls.style = 0;
8032     cls.lpfnWndProc = MsgConversionProcW;
8033     cls.cbClsExtra = 0;
8034     cls.cbWndExtra = 0;
8035     cls.hInstance = GetModuleHandleW(NULL);
8036     cls.hIcon = NULL;
8037     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
8038     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
8039     cls.lpszMenuName = NULL;
8040     cls.lpszClassName = wszMsgConversionClass;
8041     /* this call will fail on Win9x, but that doesn't matter as this test is
8042      * meaningless on those platforms */
8043     if(!RegisterClassW(&cls)) return;
8044
8045     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
8046                            100, 100, 200, 200, 0, 0, 0, NULL);
8047     ok(hwnd != NULL, "Window creation failed\n");
8048
8049     /* {W, A} -> A */
8050
8051     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
8052     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8053     ok(lRes == 0, "String should have been converted\n");
8054     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8055     ok(lRes == 1, "String shouldn't have been converted\n");
8056
8057     /* {W, A} -> W */
8058
8059     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
8060     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8061     ok(lRes == 1, "String shouldn't have been converted\n");
8062     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8063     ok(lRes == 1, "String shouldn't have been converted\n");
8064
8065     /* Synchronous messages */
8066
8067     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8068     ok(lRes == 0, "String should have been converted\n");
8069     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8070     ok(lRes == 1, "String shouldn't have been converted\n");
8071
8072     /* Asynchronous messages */
8073
8074     SetLastError(0);
8075     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8076     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8077         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8078     SetLastError(0);
8079     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8080     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8081         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8082     SetLastError(0);
8083     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8084     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8085         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8086     SetLastError(0);
8087     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8088     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8089         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8090     SetLastError(0);
8091     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8092     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8093         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8094     SetLastError(0);
8095     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8096     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8097         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8098     SetLastError(0);
8099     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8100     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8101         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8102     SetLastError(0);
8103     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8104     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8105         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8106
8107     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8108
8109     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8110                           WS_OVERLAPPEDWINDOW,
8111                           100, 100, 200, 200, 0, 0, 0, NULL);
8112     assert(hwnd);
8113     flush_sequence();
8114     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8115     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8116     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8117         "got bad length %ld\n", lRes );
8118
8119     flush_sequence();
8120     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8121                             hwnd, WM_GETTEXTLENGTH, 0, 0);
8122     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8123     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8124         "got bad length %ld\n", lRes );
8125
8126     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8127     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8128     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8129     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8130                                      NULL, 0, NULL, NULL ) ||
8131         broken(lRes == lstrlenW(dummy_window_text) + 37),
8132         "got bad length %ld\n", lRes );
8133
8134     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
8135     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8136     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8137                                      NULL, 0, NULL, NULL ) ||
8138         broken(lRes == lstrlenW(dummy_window_text) + 37),
8139         "got bad length %ld\n", lRes );
8140
8141     ret = DestroyWindow(hwnd);
8142     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8143 }
8144
8145 struct timer_info
8146 {
8147     HWND hWnd;
8148     HANDLE handles[2];
8149     DWORD id;
8150 };
8151
8152 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8153 {
8154 }
8155
8156 #define TIMER_ID  0x19
8157
8158 static DWORD WINAPI timer_thread_proc(LPVOID x)
8159 {
8160     struct timer_info *info = x;
8161     DWORD r;
8162
8163     r = KillTimer(info->hWnd, 0x19);
8164     ok(r,"KillTimer failed in thread\n");
8165     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8166     ok(r,"SetTimer failed in thread\n");
8167     ok(r==TIMER_ID,"SetTimer id different\n");
8168     r = SetEvent(info->handles[0]);
8169     ok(r,"SetEvent failed in thread\n");
8170     return 0;
8171 }
8172
8173 static void test_timers(void)
8174 {
8175     struct timer_info info;
8176     DWORD id;
8177
8178     info.hWnd = CreateWindow ("TestWindowClass", NULL,
8179        WS_OVERLAPPEDWINDOW ,
8180        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8181        NULL, NULL, 0);
8182
8183     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8184     ok(info.id, "SetTimer failed\n");
8185     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8186     info.handles[0] = CreateEvent(NULL,0,0,NULL);
8187     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8188
8189     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8190
8191     WaitForSingleObject(info.handles[1], INFINITE);
8192
8193     CloseHandle(info.handles[0]);
8194     CloseHandle(info.handles[1]);
8195
8196     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8197
8198     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8199 }
8200
8201 static int count = 0;
8202 static VOID CALLBACK callback_count(
8203     HWND hwnd,
8204     UINT uMsg,
8205     UINT_PTR idEvent,
8206     DWORD dwTime
8207 )
8208 {
8209     count++;
8210 }
8211
8212 static void test_timers_no_wnd(void)
8213 {
8214     UINT_PTR id, id2;
8215     MSG msg;
8216
8217     count = 0;
8218     id = SetTimer(NULL, 0, 100, callback_count);
8219     ok(id != 0, "did not get id from SetTimer.\n");
8220     id2 = SetTimer(NULL, id, 200, callback_count);
8221     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8222     Sleep(150);
8223     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8224     ok(count == 0, "did not get zero count as expected (%i).\n", count);
8225     Sleep(150);
8226     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8227     ok(count == 1, "did not get one count as expected (%i).\n", count);
8228     KillTimer(NULL, id);
8229     Sleep(250);
8230     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8231     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8232 }
8233
8234 /* Various win events with arbitrary parameters */
8235 static const struct message WmWinEventsSeq[] = {
8236     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8237     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8238     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8239     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8240     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8241     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8242     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8243     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8244     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8245     /* our win event hook ignores OBJID_CURSOR events */
8246     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8247     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8248     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8249     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8250     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8251     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8252     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8253     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8254     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8255     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8256     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8257     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8258     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8259     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8260     { 0 }
8261 };
8262 static const struct message WmWinEventCaretSeq[] = {
8263     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8264     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8265     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8266     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8267     { 0 }
8268 };
8269 static const struct message WmWinEventCaretSeq_2[] = {
8270     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8271     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8272     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8273     { 0 }
8274 };
8275 static const struct message WmWinEventAlertSeq[] = {
8276     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8277     { 0 }
8278 };
8279 static const struct message WmWinEventAlertSeq_2[] = {
8280     /* create window in the thread proc */
8281     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8282     /* our test event */
8283     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8284     { 0 }
8285 };
8286 static const struct message WmGlobalHookSeq_1[] = {
8287     /* create window in the thread proc */
8288     { HCBT_CREATEWND, hook|lparam, 0, 2 },
8289     /* our test events */
8290     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8291     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8292     { 0 }
8293 };
8294 static const struct message WmGlobalHookSeq_2[] = {
8295     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8296     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8297     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8298     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8299     { 0 }
8300 };
8301
8302 static const struct message WmMouseLLHookSeq[] = {
8303     { WM_MOUSEMOVE, hook },
8304     { WM_LBUTTONUP, hook },
8305     { WM_MOUSEMOVE, hook },
8306     { 0 }
8307 };
8308
8309 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8310                                          DWORD event,
8311                                          HWND hwnd,
8312                                          LONG object_id,
8313                                          LONG child_id,
8314                                          DWORD thread_id,
8315                                          DWORD event_time)
8316 {
8317     char buf[256];
8318
8319     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8320     {
8321         if (!lstrcmpiA(buf, "TestWindowClass") ||
8322             !lstrcmpiA(buf, "static"))
8323         {
8324             struct recvd_message msg;
8325
8326             msg.hwnd = hwnd;
8327             msg.message = event;
8328             msg.flags = winevent_hook|wparam|lparam;
8329             msg.wParam = object_id;
8330             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8331             msg.descr = "WEH_2";
8332             add_message(&msg);
8333         }
8334     }
8335 }
8336
8337 static HHOOK hCBT_global_hook;
8338 static DWORD cbt_global_hook_thread_id;
8339
8340 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
8341
8342     HWND hwnd;
8343     char buf[256];
8344
8345     if (nCode == HCBT_SYSCOMMAND)
8346     {
8347         struct recvd_message msg;
8348
8349         msg.hwnd = 0;
8350         msg.message = nCode;
8351         msg.flags = hook|wparam|lparam;
8352         msg.wParam = wParam;
8353         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8354         msg.descr = "CBT_2";
8355         add_message(&msg);
8356
8357         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8358     }
8359     /* WH_MOUSE_LL hook */
8360     if (nCode == HC_ACTION)
8361     {
8362         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8363
8364         /* we can't test for real mouse events */
8365         if (mhll->flags & LLMHF_INJECTED)
8366         {
8367             struct recvd_message msg;
8368
8369             memset (&msg, 0, sizeof (msg));
8370             msg.message = wParam;
8371             msg.flags = hook;
8372             msg.descr = "CBT_2";
8373             add_message(&msg);
8374         }
8375         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8376     }
8377
8378     /* Log also SetFocus(0) calls */
8379     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8380
8381     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8382     {
8383         if (!lstrcmpiA(buf, "TestWindowClass") ||
8384             !lstrcmpiA(buf, "static"))
8385         {
8386             struct recvd_message msg;
8387
8388             msg.hwnd = hwnd;
8389             msg.message = nCode;
8390             msg.flags = hook|wparam|lparam;
8391             msg.wParam = wParam;
8392             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8393             msg.descr = "CBT_2";
8394             add_message(&msg);
8395         }
8396     }
8397     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8398 }
8399
8400 static DWORD WINAPI win_event_global_thread_proc(void *param)
8401 {
8402     HWND hwnd;
8403     MSG msg;
8404     HANDLE hevent = *(HANDLE *)param;
8405
8406     assert(pNotifyWinEvent);
8407
8408     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8409     assert(hwnd);
8410     trace("created thread window %p\n", hwnd);
8411
8412     *(HWND *)param = hwnd;
8413
8414     flush_sequence();
8415     /* this event should be received only by our new hook proc,
8416      * an old one does not expect an event from another thread.
8417      */
8418     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8419     SetEvent(hevent);
8420
8421     while (GetMessage(&msg, 0, 0, 0))
8422     {
8423         TranslateMessage(&msg);
8424         DispatchMessage(&msg);
8425     }
8426     return 0;
8427 }
8428
8429 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8430 {
8431     HWND hwnd;
8432     MSG msg;
8433     HANDLE hevent = *(HANDLE *)param;
8434
8435     flush_sequence();
8436     /* these events should be received only by our new hook proc,
8437      * an old one does not expect an event from another thread.
8438      */
8439
8440     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8441     assert(hwnd);
8442     trace("created thread window %p\n", hwnd);
8443
8444     *(HWND *)param = hwnd;
8445
8446     /* Windows doesn't like when a thread plays games with the focus,
8447        that leads to all kinds of misbehaviours and failures to activate
8448        a window. So, better keep next lines commented out.
8449     SetFocus(0);
8450     SetFocus(hwnd);*/
8451
8452     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8453     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8454
8455     SetEvent(hevent);
8456
8457     while (GetMessage(&msg, 0, 0, 0))
8458     {
8459         TranslateMessage(&msg);
8460         DispatchMessage(&msg);
8461     }
8462     return 0;
8463 }
8464
8465 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8466 {
8467     HWND hwnd;
8468     MSG msg;
8469     HANDLE hevent = *(HANDLE *)param;
8470
8471     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8472     assert(hwnd);
8473     trace("created thread window %p\n", hwnd);
8474
8475     *(HWND *)param = hwnd;
8476
8477     flush_sequence();
8478
8479     /* Windows doesn't like when a thread plays games with the focus,
8480      * that leads to all kinds of misbehaviours and failures to activate
8481      * a window. So, better don't generate a mouse click message below.
8482      */
8483     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8484     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8485     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8486
8487     SetEvent(hevent);
8488     while (GetMessage(&msg, 0, 0, 0))
8489     {
8490         TranslateMessage(&msg);
8491         DispatchMessage(&msg);
8492     }
8493     return 0;
8494 }
8495
8496 static void test_winevents(void)
8497 {
8498     BOOL ret;
8499     MSG msg;
8500     HWND hwnd, hwnd2;
8501     UINT i;
8502     HANDLE hthread, hevent;
8503     DWORD tid;
8504     HWINEVENTHOOK hhook;
8505     const struct message *events = WmWinEventsSeq;
8506
8507     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8508                            WS_OVERLAPPEDWINDOW,
8509                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8510                            NULL, NULL, 0);
8511     assert(hwnd);
8512
8513     /****** start of global hook test *************/
8514     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8515     if (!hCBT_global_hook)
8516     {
8517         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8518         skip( "cannot set global hook\n" );
8519         return;
8520     }
8521
8522     hevent = CreateEventA(NULL, 0, 0, NULL);
8523     assert(hevent);
8524     hwnd2 = hevent;
8525
8526     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8527     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8528
8529     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8530
8531     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8532
8533     flush_sequence();
8534     /* this one should be received only by old hook proc */
8535     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8536     /* this one should be received only by old hook proc */
8537     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8538
8539     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8540
8541     ret = UnhookWindowsHookEx(hCBT_global_hook);
8542     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8543
8544     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8545     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8546     CloseHandle(hthread);
8547     CloseHandle(hevent);
8548     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8549     /****** end of global hook test *************/
8550
8551     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8552     {
8553         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8554         return;
8555     }
8556
8557     flush_sequence();
8558
8559     if (0)
8560     {
8561     /* this test doesn't pass under Win9x */
8562     /* win2k ignores events with hwnd == 0 */
8563     SetLastError(0xdeadbeef);
8564     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8565     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8566        GetLastError() == 0xdeadbeef, /* Win9x */
8567        "unexpected error %d\n", GetLastError());
8568     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8569     }
8570
8571     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8572         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8573
8574     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8575
8576     /****** start of event filtering test *************/
8577     hhook = pSetWinEventHook(
8578         EVENT_OBJECT_SHOW, /* 0x8002 */
8579         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8580         GetModuleHandleA(0), win_event_global_hook_proc,
8581         GetCurrentProcessId(), 0,
8582         WINEVENT_INCONTEXT);
8583     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8584
8585     hevent = CreateEventA(NULL, 0, 0, NULL);
8586     assert(hevent);
8587     hwnd2 = hevent;
8588
8589     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8590     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8591
8592     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8593
8594     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8595
8596     flush_sequence();
8597     /* this one should be received only by old hook proc */
8598     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8599     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8600     /* this one should be received only by old hook proc */
8601     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8602
8603     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8604
8605     ret = pUnhookWinEvent(hhook);
8606     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8607
8608     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8609     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8610     CloseHandle(hthread);
8611     CloseHandle(hevent);
8612     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8613     /****** end of event filtering test *************/
8614
8615     /****** start of out of context event test *************/
8616     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8617         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8618         WINEVENT_OUTOFCONTEXT);
8619     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8620
8621     hevent = CreateEventA(NULL, 0, 0, NULL);
8622     assert(hevent);
8623     hwnd2 = hevent;
8624
8625     flush_sequence();
8626
8627     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8628     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8629
8630     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8631
8632     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8633     /* process pending winevent messages */
8634     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8635     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8636
8637     flush_sequence();
8638     /* this one should be received only by old hook proc */
8639     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8640     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8641     /* this one should be received only by old hook proc */
8642     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8643
8644     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8645     /* process pending winevent messages */
8646     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8647     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8648
8649     ret = pUnhookWinEvent(hhook);
8650     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8651
8652     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8653     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8654     CloseHandle(hthread);
8655     CloseHandle(hevent);
8656     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8657     /****** end of out of context event test *************/
8658
8659     /****** start of MOUSE_LL hook test *************/
8660     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8661     /* WH_MOUSE_LL is not supported on Win9x platforms */
8662     if (!hCBT_global_hook)
8663     {
8664         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8665         goto skip_mouse_ll_hook_test;
8666     }
8667
8668     hevent = CreateEventA(NULL, 0, 0, NULL);
8669     assert(hevent);
8670     hwnd2 = hevent;
8671
8672     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8673     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8674
8675     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8676         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8677
8678     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8679     flush_sequence();
8680
8681     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8682     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8683     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8684
8685     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8686
8687     ret = UnhookWindowsHookEx(hCBT_global_hook);
8688     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8689
8690     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8691     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8692     CloseHandle(hthread);
8693     CloseHandle(hevent);
8694     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8695     /****** end of MOUSE_LL hook test *************/
8696 skip_mouse_ll_hook_test:
8697
8698     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8699 }
8700
8701 static void test_set_hook(void)
8702 {
8703     BOOL ret;
8704     HHOOK hhook;
8705     HWINEVENTHOOK hwinevent_hook;
8706
8707     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8708     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8709     UnhookWindowsHookEx(hhook);
8710
8711     if (0)
8712     {
8713     /* this test doesn't pass under Win9x: BUG! */
8714     SetLastError(0xdeadbeef);
8715     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8716     ok(!hhook, "global hook requires hModule != 0\n");
8717     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8718     }
8719
8720     SetLastError(0xdeadbeef);
8721     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8722     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8723     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8724        GetLastError() == 0xdeadbeef, /* Win9x */
8725        "unexpected error %d\n", GetLastError());
8726
8727     SetLastError(0xdeadbeef);
8728     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8729     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8730        GetLastError() == 0xdeadbeef, /* Win9x */
8731        "unexpected error %d\n", GetLastError());
8732
8733     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8734
8735     /* even process local incontext hooks require hmodule */
8736     SetLastError(0xdeadbeef);
8737     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8738         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8739     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8740     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8741        GetLastError() == 0xdeadbeef, /* Win9x */
8742        "unexpected error %d\n", GetLastError());
8743
8744     /* even thread local incontext hooks require hmodule */
8745     SetLastError(0xdeadbeef);
8746     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8747         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8748     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8749     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8750        GetLastError() == 0xdeadbeef, /* Win9x */
8751        "unexpected error %d\n", GetLastError());
8752
8753     if (0)
8754     {
8755     /* these 3 tests don't pass under Win9x */
8756     SetLastError(0xdeadbeef);
8757     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8758         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8759     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8760     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8761
8762     SetLastError(0xdeadbeef);
8763     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8764         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8765     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8766     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8767
8768     SetLastError(0xdeadbeef);
8769     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8770         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8771     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8772     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8773     }
8774
8775     SetLastError(0xdeadbeef);
8776     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8777         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8778     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8779     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8780     ret = pUnhookWinEvent(hwinevent_hook);
8781     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8782
8783 todo_wine {
8784     /* This call succeeds under win2k SP4, but fails under Wine.
8785        Does win2k test/use passed process id? */
8786     SetLastError(0xdeadbeef);
8787     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8788         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8789     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8790     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8791     ret = pUnhookWinEvent(hwinevent_hook);
8792     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8793 }
8794
8795     SetLastError(0xdeadbeef);
8796     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8797     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8798         GetLastError() == 0xdeadbeef, /* Win9x */
8799         "unexpected error %d\n", GetLastError());
8800 }
8801
8802 static const struct message ScrollWindowPaint1[] = {
8803     { WM_PAINT, sent },
8804     { WM_ERASEBKGND, sent|beginpaint },
8805     { WM_GETTEXTLENGTH, sent|optional },
8806     { WM_PAINT, sent|optional },
8807     { WM_NCPAINT, sent|beginpaint|optional },
8808     { WM_GETTEXT, sent|beginpaint|optional },
8809     { WM_GETTEXT, sent|beginpaint|optional },
8810     { WM_GETTEXT, sent|beginpaint|optional },
8811     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8812     { WM_ERASEBKGND, sent|beginpaint|optional },
8813     { 0 }
8814 };
8815
8816 static const struct message ScrollWindowPaint2[] = {
8817     { WM_PAINT, sent },
8818     { 0 }
8819 };
8820
8821 static void test_scrollwindowex(void)
8822 {
8823     HWND hwnd, hchild;
8824     RECT rect={0,0,130,130};
8825
8826     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8827             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8828             100, 100, 200, 200, 0, 0, 0, NULL);
8829     ok (hwnd != 0, "Failed to create overlapped window\n");
8830     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8831             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8832             10, 10, 150, 150, hwnd, 0, 0, NULL);
8833     ok (hchild != 0, "Failed to create child\n");
8834     UpdateWindow(hwnd);
8835     flush_events();
8836     flush_sequence();
8837
8838     /* scroll without the child window */
8839     trace("start scroll\n");
8840     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8841             SW_ERASE|SW_INVALIDATE);
8842     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8843     trace("end scroll\n");
8844     flush_sequence();
8845     flush_events();
8846     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8847     flush_events();
8848     flush_sequence();
8849
8850     /* Now without the SW_ERASE flag */
8851     trace("start scroll\n");
8852     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8853     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8854     trace("end scroll\n");
8855     flush_sequence();
8856     flush_events();
8857     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8858     flush_events();
8859     flush_sequence();
8860
8861     /* now scroll the child window as well */
8862     trace("start scroll\n");
8863     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8864             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8865     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8866     /* windows sometimes a WM_MOVE */
8867     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8868     trace("end scroll\n");
8869     flush_sequence();
8870     flush_events();
8871     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8872     flush_events();
8873     flush_sequence();
8874
8875     /* now scroll with ScrollWindow() */
8876     trace("start scroll with ScrollWindow\n");
8877     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8878     trace("end scroll\n");
8879     flush_sequence();
8880     flush_events();
8881     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8882
8883     ok(DestroyWindow(hchild), "failed to destroy window\n");
8884     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8885     flush_sequence();
8886 }
8887
8888 static const struct message destroy_window_with_children[] = {
8889     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8890     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8891     { 0x0090, sent|optional },
8892     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8893     { 0x0090, sent|optional },
8894     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8895     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8896     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8897     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8898     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8899     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8900     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8901     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8902     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8903     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8904     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8905     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8906     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8907     { 0 }
8908 };
8909
8910 static void test_DestroyWindow(void)
8911 {
8912     BOOL ret;
8913     HWND parent, child1, child2, child3, child4, test;
8914     UINT_PTR child_id = WND_CHILD_ID + 1;
8915
8916     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8917                              100, 100, 200, 200, 0, 0, 0, NULL);
8918     assert(parent != 0);
8919     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8920                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8921     assert(child1 != 0);
8922     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8923                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8924     assert(child2 != 0);
8925     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8926                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8927     assert(child3 != 0);
8928     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8929                              0, 0, 50, 50, parent, 0, 0, NULL);
8930     assert(child4 != 0);
8931
8932     /* test owner/parent of child2 */
8933     test = GetParent(child2);
8934     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8935     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8936     if(pGetAncestor) {
8937         test = pGetAncestor(child2, GA_PARENT);
8938         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8939     }
8940     test = GetWindow(child2, GW_OWNER);
8941     ok(!test, "wrong owner %p\n", test);
8942
8943     test = SetParent(child2, parent);
8944     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8945
8946     /* test owner/parent of the parent */
8947     test = GetParent(parent);
8948     ok(!test, "wrong parent %p\n", test);
8949     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8950     if(pGetAncestor) {
8951         test = pGetAncestor(parent, GA_PARENT);
8952         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8953     }
8954     test = GetWindow(parent, GW_OWNER);
8955     ok(!test, "wrong owner %p\n", test);
8956
8957     /* test owner/parent of child1 */
8958     test = GetParent(child1);
8959     ok(test == parent, "wrong parent %p\n", test);
8960     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8961     if(pGetAncestor) {
8962         test = pGetAncestor(child1, GA_PARENT);
8963         ok(test == parent, "wrong parent %p\n", test);
8964     }
8965     test = GetWindow(child1, GW_OWNER);
8966     ok(!test, "wrong owner %p\n", test);
8967
8968     /* test owner/parent of child2 */
8969     test = GetParent(child2);
8970     ok(test == parent, "wrong parent %p\n", test);
8971     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8972     if(pGetAncestor) {
8973         test = pGetAncestor(child2, GA_PARENT);
8974         ok(test == parent, "wrong parent %p\n", test);
8975     }
8976     test = GetWindow(child2, GW_OWNER);
8977     ok(!test, "wrong owner %p\n", test);
8978
8979     /* test owner/parent of child3 */
8980     test = GetParent(child3);
8981     ok(test == child1, "wrong parent %p\n", test);
8982     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8983     if(pGetAncestor) {
8984         test = pGetAncestor(child3, GA_PARENT);
8985         ok(test == child1, "wrong parent %p\n", test);
8986     }
8987     test = GetWindow(child3, GW_OWNER);
8988     ok(!test, "wrong owner %p\n", test);
8989
8990     /* test owner/parent of child4 */
8991     test = GetParent(child4);
8992     ok(test == parent, "wrong parent %p\n", test);
8993     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8994     if(pGetAncestor) {
8995         test = pGetAncestor(child4, GA_PARENT);
8996         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8997     }
8998     test = GetWindow(child4, GW_OWNER);
8999     ok(test == parent, "wrong owner %p\n", test);
9000
9001     flush_sequence();
9002
9003     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
9004            parent, child1, child2, child3, child4);
9005
9006     SetCapture(child4);
9007     test = GetCapture();
9008     ok(test == child4, "wrong capture window %p\n", test);
9009
9010     test_DestroyWindow_flag = TRUE;
9011     ret = DestroyWindow(parent);
9012     ok( ret, "DestroyWindow() error %d\n", GetLastError());
9013     test_DestroyWindow_flag = FALSE;
9014     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
9015
9016     ok(!IsWindow(parent), "parent still exists\n");
9017     ok(!IsWindow(child1), "child1 still exists\n");
9018     ok(!IsWindow(child2), "child2 still exists\n");
9019     ok(!IsWindow(child3), "child3 still exists\n");
9020     ok(!IsWindow(child4), "child4 still exists\n");
9021
9022     test = GetCapture();
9023     ok(!test, "wrong capture window %p\n", test);
9024 }
9025
9026
9027 static const struct message WmDispatchPaint[] = {
9028     { WM_NCPAINT, sent },
9029     { WM_GETTEXT, sent|defwinproc|optional },
9030     { WM_GETTEXT, sent|defwinproc|optional },
9031     { WM_ERASEBKGND, sent },
9032     { 0 }
9033 };
9034
9035 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9036 {
9037     if (message == WM_PAINT) return 0;
9038     return MsgCheckProcA( hwnd, message, wParam, lParam );
9039 }
9040
9041 static void test_DispatchMessage(void)
9042 {
9043     RECT rect;
9044     MSG msg;
9045     int count;
9046     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9047                                100, 100, 200, 200, 0, 0, 0, NULL);
9048     ShowWindow( hwnd, SW_SHOW );
9049     UpdateWindow( hwnd );
9050     flush_events();
9051     flush_sequence();
9052     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
9053
9054     SetRect( &rect, -5, -5, 5, 5 );
9055     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9056     count = 0;
9057     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9058     {
9059         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9060         else
9061         {
9062             flush_sequence();
9063             DispatchMessage( &msg );
9064             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
9065             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9066             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
9067             if (++count > 10) break;
9068         }
9069     }
9070     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
9071
9072     trace("now without DispatchMessage\n");
9073     flush_sequence();
9074     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9075     count = 0;
9076     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9077     {
9078         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9079         else
9080         {
9081             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9082             flush_sequence();
9083             /* this will send WM_NCCPAINT just like DispatchMessage does */
9084             GetUpdateRgn( hwnd, hrgn, TRUE );
9085             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9086             DeleteObject( hrgn );
9087             GetClientRect( hwnd, &rect );
9088             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
9089             ok( !count, "Got multiple WM_PAINTs\n" );
9090             if (++count > 10) break;
9091         }
9092     }
9093     DestroyWindow(hwnd);
9094 }
9095
9096
9097 static const struct message WmUser[] = {
9098     { WM_USER, sent },
9099     { 0 }
9100 };
9101
9102 struct sendmsg_info
9103 {
9104     HWND  hwnd;
9105     DWORD timeout;
9106     DWORD ret;
9107 };
9108
9109 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9110 {
9111     struct sendmsg_info *info = arg;
9112     SetLastError( 0xdeadbeef );
9113     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9114     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9115                         broken(GetLastError() == 0),  /* win9x */
9116                         "unexpected error %d\n", GetLastError());
9117     return 0;
9118 }
9119
9120 static void wait_for_thread( HANDLE thread )
9121 {
9122     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9123     {
9124         MSG msg;
9125         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
9126     }
9127 }
9128
9129 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9130 {
9131     if (message == WM_USER) Sleep(200);
9132     return MsgCheckProcA( hwnd, message, wParam, lParam );
9133 }
9134
9135 static void test_SendMessageTimeout(void)
9136 {
9137     HANDLE thread;
9138     struct sendmsg_info info;
9139     DWORD tid;
9140     BOOL is_win9x;
9141
9142     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9143                                100, 100, 200, 200, 0, 0, 0, NULL);
9144     flush_events();
9145     flush_sequence();
9146
9147     info.timeout = 1000;
9148     info.ret = 0xdeadbeef;
9149     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9150     wait_for_thread( thread );
9151     CloseHandle( thread );
9152     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9153     ok_sequence( WmUser, "WmUser", FALSE );
9154
9155     info.timeout = 1;
9156     info.ret = 0xdeadbeef;
9157     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9158     Sleep(100);  /* SendMessageTimeout should time out here */
9159     wait_for_thread( thread );
9160     CloseHandle( thread );
9161     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9162     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9163
9164     /* 0 means infinite timeout (but not on win9x) */
9165     info.timeout = 0;
9166     info.ret = 0xdeadbeef;
9167     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9168     Sleep(100);
9169     wait_for_thread( thread );
9170     CloseHandle( thread );
9171     is_win9x = !info.ret;
9172     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9173     else ok_sequence( WmUser, "WmUser", FALSE );
9174
9175     /* timeout is treated as signed despite the prototype (but not on win9x) */
9176     info.timeout = 0x7fffffff;
9177     info.ret = 0xdeadbeef;
9178     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9179     Sleep(100);
9180     wait_for_thread( thread );
9181     CloseHandle( thread );
9182     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9183     ok_sequence( WmUser, "WmUser", FALSE );
9184
9185     info.timeout = 0x80000000;
9186     info.ret = 0xdeadbeef;
9187     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9188     Sleep(100);
9189     wait_for_thread( thread );
9190     CloseHandle( thread );
9191     if (is_win9x)
9192     {
9193         ok( info.ret == 1, "SendMessageTimeout failed\n" );
9194         ok_sequence( WmUser, "WmUser", FALSE );
9195     }
9196     else
9197     {
9198         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9199         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9200     }
9201
9202     /* now check for timeout during message processing */
9203     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9204     info.timeout = 100;
9205     info.ret = 0xdeadbeef;
9206     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9207     wait_for_thread( thread );
9208     CloseHandle( thread );
9209     /* we should time out but still get the message */
9210     ok( info.ret == 0, "SendMessageTimeout failed\n" );
9211     ok_sequence( WmUser, "WmUser", FALSE );
9212
9213     DestroyWindow( info.hwnd );
9214 }
9215
9216
9217 /****************** edit message test *************************/
9218 #define ID_EDIT 0x1234
9219 static const struct message sl_edit_setfocus[] =
9220 {
9221     { HCBT_SETFOCUS, hook },
9222     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9223     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9224     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9225     { WM_SETFOCUS, sent|wparam, 0 },
9226     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9227     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9228     { WM_CTLCOLOREDIT, sent|parent },
9229     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9230     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9231     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9232     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9233     { 0 }
9234 };
9235 static const struct message ml_edit_setfocus[] =
9236 {
9237     { HCBT_SETFOCUS, hook },
9238     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9239     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9240     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9241     { WM_SETFOCUS, sent|wparam, 0 },
9242     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9243     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9244     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9245     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9246     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9247     { 0 }
9248 };
9249 static const struct message sl_edit_killfocus[] =
9250 {
9251     { HCBT_SETFOCUS, hook },
9252     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9253     { WM_KILLFOCUS, sent|wparam, 0 },
9254     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9255     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9256     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9257     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9258     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9259     { 0 }
9260 };
9261 static const struct message sl_edit_lbutton_dblclk[] =
9262 {
9263     { WM_LBUTTONDBLCLK, sent },
9264     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9265     { 0 }
9266 };
9267 static const struct message sl_edit_lbutton_down[] =
9268 {
9269     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9270     { HCBT_SETFOCUS, hook },
9271     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9272     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9273     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9274     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9275     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9276     { WM_CTLCOLOREDIT, sent|parent },
9277     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9278     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9279     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9280     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9281     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9282     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9283     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9284     { WM_CTLCOLOREDIT, sent|parent|optional },
9285     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9286     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9287     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9288     { 0 }
9289 };
9290 static const struct message ml_edit_lbutton_down[] =
9291 {
9292     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9293     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9294     { HCBT_SETFOCUS, hook },
9295     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9296     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9297     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9298     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9299     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9300     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9301     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9302     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9303     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9304     { 0 }
9305 };
9306 static const struct message sl_edit_lbutton_up[] =
9307 {
9308     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9309     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9310     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9311     { WM_CAPTURECHANGED, sent|defwinproc },
9312     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9313     { 0 }
9314 };
9315 static const struct message ml_edit_lbutton_up[] =
9316 {
9317     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9318     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9319     { WM_CAPTURECHANGED, sent|defwinproc },
9320     { 0 }
9321 };
9322
9323 static WNDPROC old_edit_proc;
9324
9325 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9326 {
9327     static LONG defwndproc_counter = 0;
9328     LRESULT ret;
9329     struct recvd_message msg;
9330
9331     if (ignore_message( message )) return 0;
9332
9333     msg.hwnd = hwnd;
9334     msg.message = message;
9335     msg.flags = sent|wparam|lparam;
9336     if (defwndproc_counter) msg.flags |= defwinproc;
9337     msg.wParam = wParam;
9338     msg.lParam = lParam;
9339     msg.descr = "edit";
9340     add_message(&msg);
9341
9342     defwndproc_counter++;
9343     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9344     defwndproc_counter--;
9345
9346     return ret;
9347 }
9348
9349 static void subclass_edit(void)
9350 {
9351     WNDCLASSA cls;
9352
9353     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9354
9355     old_edit_proc = cls.lpfnWndProc;
9356
9357     cls.hInstance = GetModuleHandle(0);
9358     cls.lpfnWndProc = edit_hook_proc;
9359     cls.lpszClassName = "my_edit_class";
9360     UnregisterClass(cls.lpszClassName, cls.hInstance);
9361     if (!RegisterClassA(&cls)) assert(0);
9362 }
9363
9364 static void test_edit_messages(void)
9365 {
9366     HWND hwnd, parent;
9367     DWORD dlg_code;
9368
9369     subclass_edit();
9370     log_all_parent_messages++;
9371
9372     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9373                              100, 100, 200, 200, 0, 0, 0, NULL);
9374     ok (parent != 0, "Failed to create parent window\n");
9375
9376     /* test single line edit */
9377     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9378                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9379     ok(hwnd != 0, "Failed to create edit window\n");
9380
9381     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9382     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9383
9384     ShowWindow(hwnd, SW_SHOW);
9385     UpdateWindow(hwnd);
9386     SetFocus(0);
9387     flush_sequence();
9388
9389     SetFocus(hwnd);
9390     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9391
9392     SetFocus(0);
9393     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9394
9395     SetFocus(0);
9396     ReleaseCapture();
9397     flush_sequence();
9398
9399     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9400     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9401
9402     SetFocus(0);
9403     ReleaseCapture();
9404     flush_sequence();
9405
9406     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9407     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9408
9409     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9410     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9411
9412     DestroyWindow(hwnd);
9413
9414     /* test multiline edit */
9415     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9416                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9417     ok(hwnd != 0, "Failed to create edit window\n");
9418
9419     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9420     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9421        "wrong dlg_code %08x\n", dlg_code);
9422
9423     ShowWindow(hwnd, SW_SHOW);
9424     UpdateWindow(hwnd);
9425     SetFocus(0);
9426     flush_sequence();
9427
9428     SetFocus(hwnd);
9429     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9430
9431     SetFocus(0);
9432     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9433
9434     SetFocus(0);
9435     ReleaseCapture();
9436     flush_sequence();
9437
9438     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9439     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9440
9441     SetFocus(0);
9442     ReleaseCapture();
9443     flush_sequence();
9444
9445     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9446     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9447
9448     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9449     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9450
9451     DestroyWindow(hwnd);
9452     DestroyWindow(parent);
9453
9454     log_all_parent_messages--;
9455 }
9456
9457 /**************************** End of Edit test ******************************/
9458
9459 static const struct message WmKeyDownSkippedSeq[] =
9460 {
9461     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9462     { 0 }
9463 };
9464 static const struct message WmKeyDownWasDownSkippedSeq[] =
9465 {
9466     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9467     { 0 }
9468 };
9469 static const struct message WmKeyUpSkippedSeq[] =
9470 {
9471     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9472     { 0 }
9473 };
9474 static const struct message WmUserKeyUpSkippedSeq[] =
9475 {
9476     { WM_USER, sent },
9477     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9478     { 0 }
9479 };
9480
9481 #define EV_STOP 0
9482 #define EV_SENDMSG 1
9483 #define EV_ACK 2
9484
9485 struct peekmsg_info
9486 {
9487     HWND  hwnd;
9488     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9489 };
9490
9491 static DWORD CALLBACK send_msg_thread_2(void *param)
9492 {
9493     DWORD ret;
9494     struct peekmsg_info *info = param;
9495
9496     trace("thread: looping\n");
9497     SetEvent(info->hevent[EV_ACK]);
9498
9499     while (1)
9500     {
9501         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9502
9503         switch (ret)
9504         {
9505         case WAIT_OBJECT_0 + EV_STOP:
9506             trace("thread: exiting\n");
9507             return 0;
9508
9509         case WAIT_OBJECT_0 + EV_SENDMSG:
9510             trace("thread: sending message\n");
9511             ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
9512             ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
9513             SetEvent(info->hevent[EV_ACK]);
9514             break;
9515
9516         default:
9517             trace("unexpected return: %04x\n", ret);
9518             assert(0);
9519             break;
9520         }
9521     }
9522     return 0;
9523 }
9524
9525 static void test_PeekMessage(void)
9526 {
9527     MSG msg;
9528     HANDLE hthread;
9529     DWORD tid, qstatus;
9530     UINT qs_all_input = QS_ALLINPUT;
9531     UINT qs_input = QS_INPUT;
9532     BOOL ret;
9533     struct peekmsg_info info;
9534
9535     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9536                               100, 100, 200, 200, 0, 0, 0, NULL);
9537     assert(info.hwnd);
9538     ShowWindow(info.hwnd, SW_SHOW);
9539     UpdateWindow(info.hwnd);
9540     SetFocus(info.hwnd);
9541
9542     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9543     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9544     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9545
9546     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9547     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9548
9549     flush_events();
9550     flush_sequence();
9551
9552     SetLastError(0xdeadbeef);
9553     qstatus = GetQueueStatus(qs_all_input);
9554     if (GetLastError() == ERROR_INVALID_FLAGS)
9555     {
9556         trace("QS_RAWINPUT not supported on this platform\n");
9557         qs_all_input &= ~QS_RAWINPUT;
9558         qs_input &= ~QS_RAWINPUT;
9559     }
9560     if (qstatus & QS_POSTMESSAGE)
9561     {
9562         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9563         qstatus = GetQueueStatus(qs_all_input);
9564     }
9565     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9566
9567     trace("signalling to send message\n");
9568     SetEvent(info.hevent[EV_SENDMSG]);
9569     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9570
9571     /* pass invalid QS_xxxx flags */
9572     SetLastError(0xdeadbeef);
9573     qstatus = GetQueueStatus(0xffffffff);
9574     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9575     if (!qstatus)
9576     {
9577         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9578         qstatus = GetQueueStatus(qs_all_input);
9579     }
9580     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9581     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9582        "wrong qstatus %08x\n", qstatus);
9583
9584     msg.message = 0;
9585     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9586     ok(!ret,
9587        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9588         msg.message);
9589     ok_sequence(WmUser, "WmUser", FALSE);
9590
9591     qstatus = GetQueueStatus(qs_all_input);
9592     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9593
9594     keybd_event('N', 0, 0, 0);
9595     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9596     qstatus = GetQueueStatus(qs_all_input);
9597     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9598     {
9599         skip( "queuing key events not supported\n" );
9600         goto done;
9601     }
9602     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9603        /* keybd_event seems to trigger a sent message on NT4 */
9604        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9605        "wrong qstatus %08x\n", qstatus);
9606
9607     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9608     qstatus = GetQueueStatus(qs_all_input);
9609     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9610        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9611        "wrong qstatus %08x\n", qstatus);
9612
9613     InvalidateRect(info.hwnd, NULL, FALSE);
9614     qstatus = GetQueueStatus(qs_all_input);
9615     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9616        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9617        "wrong qstatus %08x\n", qstatus);
9618
9619     trace("signalling to send message\n");
9620     SetEvent(info.hevent[EV_SENDMSG]);
9621     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9622
9623     qstatus = GetQueueStatus(qs_all_input);
9624     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9625        "wrong qstatus %08x\n", qstatus);
9626
9627     msg.message = 0;
9628     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9629     if (ret && msg.message == WM_CHAR)
9630     {
9631         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9632         goto done;
9633     }
9634     ok(!ret,
9635        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9636         msg.message);
9637     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9638     {
9639         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9640         goto done;
9641     }
9642     ok_sequence(WmUser, "WmUser", FALSE);
9643
9644     qstatus = GetQueueStatus(qs_all_input);
9645     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9646        "wrong qstatus %08x\n", qstatus);
9647
9648     trace("signalling to send message\n");
9649     SetEvent(info.hevent[EV_SENDMSG]);
9650     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9651
9652     qstatus = GetQueueStatus(qs_all_input);
9653     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9654        "wrong qstatus %08x\n", qstatus);
9655
9656     msg.message = 0;
9657     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9658     ok(!ret,
9659        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9660         msg.message);
9661     ok_sequence(WmUser, "WmUser", FALSE);
9662
9663     qstatus = GetQueueStatus(qs_all_input);
9664     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9665        "wrong qstatus %08x\n", qstatus);
9666
9667     msg.message = 0;
9668     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9669     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9670        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9671        ret, msg.message, msg.wParam);
9672     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9673
9674     qstatus = GetQueueStatus(qs_all_input);
9675     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9676        "wrong qstatus %08x\n", qstatus);
9677
9678     msg.message = 0;
9679     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9680     ok(!ret,
9681        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9682         msg.message);
9683     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9684
9685     qstatus = GetQueueStatus(qs_all_input);
9686     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9687        "wrong qstatus %08x\n", qstatus);
9688
9689     msg.message = 0;
9690     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9691     ok(ret && msg.message == WM_PAINT,
9692        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9693     DispatchMessageA(&msg);
9694     ok_sequence(WmPaint, "WmPaint", FALSE);
9695
9696     qstatus = GetQueueStatus(qs_all_input);
9697     ok(qstatus == MAKELONG(0, QS_KEY),
9698        "wrong qstatus %08x\n", qstatus);
9699
9700     msg.message = 0;
9701     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9702     ok(!ret,
9703        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9704         msg.message);
9705     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9706
9707     qstatus = GetQueueStatus(qs_all_input);
9708     ok(qstatus == MAKELONG(0, QS_KEY),
9709        "wrong qstatus %08x\n", qstatus);
9710
9711     trace("signalling to send message\n");
9712     SetEvent(info.hevent[EV_SENDMSG]);
9713     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9714
9715     qstatus = GetQueueStatus(qs_all_input);
9716     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9717        "wrong qstatus %08x\n", qstatus);
9718
9719     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9720
9721     qstatus = GetQueueStatus(qs_all_input);
9722     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9723        "wrong qstatus %08x\n", qstatus);
9724
9725     msg.message = 0;
9726     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9727     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9728        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9729        ret, msg.message, msg.wParam);
9730     ok_sequence(WmUser, "WmUser", FALSE);
9731
9732     qstatus = GetQueueStatus(qs_all_input);
9733     ok(qstatus == MAKELONG(0, QS_KEY),
9734        "wrong qstatus %08x\n", qstatus);
9735
9736     msg.message = 0;
9737     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9738     ok(!ret,
9739        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9740         msg.message);
9741     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9742
9743     qstatus = GetQueueStatus(qs_all_input);
9744     ok(qstatus == MAKELONG(0, QS_KEY),
9745        "wrong qstatus %08x\n", qstatus);
9746
9747     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9748
9749     qstatus = GetQueueStatus(qs_all_input);
9750     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9751        "wrong qstatus %08x\n", qstatus);
9752
9753     trace("signalling to send message\n");
9754     SetEvent(info.hevent[EV_SENDMSG]);
9755     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9756
9757     qstatus = GetQueueStatus(qs_all_input);
9758     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9759        "wrong qstatus %08x\n", qstatus);
9760
9761     msg.message = 0;
9762     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9763     ok(!ret,
9764        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9765         msg.message);
9766     ok_sequence(WmUser, "WmUser", FALSE);
9767
9768     qstatus = GetQueueStatus(qs_all_input);
9769     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9770        "wrong qstatus %08x\n", qstatus);
9771
9772     msg.message = 0;
9773     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9774         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9775     else /* workaround for a missing QS_RAWINPUT support */
9776         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9777     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9778        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9779        ret, msg.message, msg.wParam);
9780     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9781
9782     qstatus = GetQueueStatus(qs_all_input);
9783     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9784        "wrong qstatus %08x\n", qstatus);
9785
9786     msg.message = 0;
9787     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9788         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9789     else /* workaround for a missing QS_RAWINPUT support */
9790         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9791     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9792        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9793        ret, msg.message, msg.wParam);
9794     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9795
9796     qstatus = GetQueueStatus(qs_all_input);
9797     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9798        "wrong qstatus %08x\n", qstatus);
9799
9800     msg.message = 0;
9801     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9802     ok(!ret,
9803        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9804         msg.message);
9805     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9806
9807     qstatus = GetQueueStatus(qs_all_input);
9808     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9809        "wrong qstatus %08x\n", qstatus);
9810
9811     msg.message = 0;
9812     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9813     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9814        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9815        ret, msg.message, msg.wParam);
9816     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9817
9818     qstatus = GetQueueStatus(qs_all_input);
9819     ok(qstatus == 0,
9820        "wrong qstatus %08x\n", qstatus);
9821
9822     msg.message = 0;
9823     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9824     ok(!ret,
9825        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9826         msg.message);
9827     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9828
9829     qstatus = GetQueueStatus(qs_all_input);
9830     ok(qstatus == 0,
9831        "wrong qstatus %08x\n", qstatus);
9832
9833     /* test whether presence of the quit flag in the queue affects
9834      * the queue state
9835      */
9836     PostQuitMessage(0x1234abcd);
9837
9838     qstatus = GetQueueStatus(qs_all_input);
9839     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9840        "wrong qstatus %08x\n", qstatus);
9841
9842     PostMessageA(info.hwnd, WM_USER, 0, 0);
9843
9844     qstatus = GetQueueStatus(qs_all_input);
9845     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9846        "wrong qstatus %08x\n", qstatus);
9847
9848     msg.message = 0;
9849     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9850     ok(ret && msg.message == WM_USER,
9851        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9852     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9853
9854     qstatus = GetQueueStatus(qs_all_input);
9855     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9856        "wrong qstatus %08x\n", qstatus);
9857
9858     msg.message = 0;
9859     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9860     ok(ret && msg.message == WM_QUIT,
9861        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9862     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9863     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9864     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9865
9866     qstatus = GetQueueStatus(qs_all_input);
9867 todo_wine {
9868     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9869        "wrong qstatus %08x\n", qstatus);
9870 }
9871
9872     msg.message = 0;
9873     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9874     ok(!ret,
9875        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9876         msg.message);
9877     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9878
9879     qstatus = GetQueueStatus(qs_all_input);
9880     ok(qstatus == 0,
9881        "wrong qstatus %08x\n", qstatus);
9882
9883     /* some GetMessage tests */
9884
9885     keybd_event('N', 0, 0, 0);
9886     qstatus = GetQueueStatus(qs_all_input);
9887     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9888
9889     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9890     qstatus = GetQueueStatus(qs_all_input);
9891     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9892
9893     if (qstatus)
9894     {
9895         ret = GetMessageA( &msg, 0, 0, 0 );
9896         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9897            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9898            ret, msg.message, msg.wParam);
9899         qstatus = GetQueueStatus(qs_all_input);
9900         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9901     }
9902
9903     if (qstatus)
9904     {
9905         ret = GetMessageA( &msg, 0, 0, 0 );
9906         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9907            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9908            ret, msg.message, msg.wParam);
9909         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9910         qstatus = GetQueueStatus(qs_all_input);
9911         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9912     }
9913
9914     keybd_event('N', 0, 0, 0);
9915     qstatus = GetQueueStatus(qs_all_input);
9916     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9917
9918     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9919     qstatus = GetQueueStatus(qs_all_input);
9920     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9921
9922     if (qstatus & (QS_KEY << 16))
9923     {
9924         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9925         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9926            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9927            ret, msg.message, msg.wParam);
9928         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9929         qstatus = GetQueueStatus(qs_all_input);
9930         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9931     }
9932
9933     if (qstatus)
9934     {
9935         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9936         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9937            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9938            ret, msg.message, msg.wParam);
9939         qstatus = GetQueueStatus(qs_all_input);
9940         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9941     }
9942
9943     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9944     qstatus = GetQueueStatus(qs_all_input);
9945     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9946
9947     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9948     qstatus = GetQueueStatus(qs_all_input);
9949     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9950
9951     trace("signalling to send message\n");
9952     SetEvent(info.hevent[EV_SENDMSG]);
9953     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9954     qstatus = GetQueueStatus(qs_all_input);
9955     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9956        "wrong qstatus %08x\n", qstatus);
9957
9958     if (qstatus & (QS_KEY << 16))
9959     {
9960         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9961         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9962            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9963            ret, msg.message, msg.wParam);
9964         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9965         qstatus = GetQueueStatus(qs_all_input);
9966         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9967     }
9968
9969     if (qstatus)
9970     {
9971         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9972         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9973            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9974            ret, msg.message, msg.wParam);
9975         qstatus = GetQueueStatus(qs_all_input);
9976         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9977     }
9978 done:
9979     trace("signalling to exit\n");
9980     SetEvent(info.hevent[EV_STOP]);
9981
9982     WaitForSingleObject(hthread, INFINITE);
9983
9984     CloseHandle(hthread);
9985     CloseHandle(info.hevent[0]);
9986     CloseHandle(info.hevent[1]);
9987     CloseHandle(info.hevent[2]);
9988
9989     DestroyWindow(info.hwnd);
9990 }
9991
9992 static void wait_move_event(HWND hwnd, int x, int y)
9993 {
9994     MSG msg;
9995     DWORD time;
9996     BOOL  ret;
9997     int go = 0;
9998
9999     time = GetTickCount();
10000     while (GetTickCount() - time < 200 && !go) {
10001         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10002         go  = ret && msg.pt.x > x && msg.pt.y > y;
10003         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
10004     }
10005 }
10006
10007 #define STEP 5
10008 static void test_PeekMessage2(void)
10009 {
10010     HWND hwnd;
10011     BOOL ret;
10012     MSG msg;
10013     UINT message;
10014     DWORD time1, time2, time3;
10015     int x1, y1, x2, y2, x3, y3;
10016     POINT pos;
10017
10018     time1 = time2 = time3 = 0;
10019     x1 = y1 = x2 = y2 = x3 = y3 = 0;
10020
10021     /* Initialise window and make sure it is ready for events */
10022     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
10023                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
10024     assert(hwnd);
10025     trace("Window for test_PeekMessage2 %p\n", hwnd);
10026     ShowWindow(hwnd, SW_SHOW);
10027     UpdateWindow(hwnd);
10028     SetFocus(hwnd);
10029     GetCursorPos(&pos);
10030     SetCursorPos(100, 100);
10031     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
10032     flush_events();
10033
10034     /* Do initial mousemove, wait until we can see it
10035        and then do our test peek with PM_NOREMOVE. */
10036     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10037     wait_move_event(hwnd, 100-STEP, 100-STEP);
10038
10039     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10040     if (!ret)
10041     {
10042         skip( "queuing mouse events not supported\n" );
10043         goto done;
10044     }
10045     else
10046     {
10047         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10048         message = msg.message;
10049         time1 = msg.time;
10050         x1 = msg.pt.x;
10051         y1 = msg.pt.y;
10052         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10053     }
10054
10055     /* Allow time to advance a bit, and then simulate the user moving their
10056      * mouse around. After that we peek again with PM_NOREMOVE.
10057      * Although the previous mousemove message was never removed, the
10058      * mousemove we now peek should reflect the recent mouse movements
10059      * because the input queue will merge the move events. */
10060     Sleep(100);
10061     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10062     wait_move_event(hwnd, x1, y1);
10063
10064     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10065     ok(ret, "no message available\n");
10066     if (ret) {
10067         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10068         message = msg.message;
10069         time2 = msg.time;
10070         x2 = msg.pt.x;
10071         y2 = msg.pt.y;
10072         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10073         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10074         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10075     }
10076
10077     /* Have another go, to drive the point home */
10078     Sleep(100);
10079     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10080     wait_move_event(hwnd, x2, y2);
10081
10082     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10083     ok(ret, "no message available\n");
10084     if (ret) {
10085         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10086         message = msg.message;
10087         time3 = msg.time;
10088         x3 = msg.pt.x;
10089         y3 = msg.pt.y;
10090         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10091         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10092         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10093     }
10094
10095 done:
10096     DestroyWindow(hwnd);
10097     SetCursorPos(pos.x, pos.y);
10098     flush_events();
10099 }
10100
10101 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10102 {
10103     struct recvd_message msg;
10104
10105     if (ignore_message( message )) return 0;
10106
10107     msg.hwnd = hwnd;
10108     msg.message = message;
10109     msg.flags = sent|wparam|lparam;
10110     msg.wParam = wp;
10111     msg.lParam = lp;
10112     msg.descr = "dialog";
10113     add_message(&msg);
10114
10115     switch (message)
10116     {
10117     case WM_INITDIALOG:
10118         PostMessage(hwnd, WM_QUIT, 0x1234, 0x5678);
10119         PostMessage(hwnd, WM_USER, 0xdead, 0xbeef);
10120         return 0;
10121
10122     case WM_GETDLGCODE:
10123         return 0;
10124
10125     case WM_USER:
10126         EndDialog(hwnd, 0);
10127         break;
10128     }
10129
10130     return 1;
10131 }
10132
10133 static const struct message WmQuitDialogSeq[] = {
10134     { HCBT_CREATEWND, hook },
10135     { WM_SETFONT, sent },
10136     { WM_INITDIALOG, sent },
10137     { WM_CHANGEUISTATE, sent|optional },
10138     { HCBT_DESTROYWND, hook },
10139     { 0x0090, sent|optional }, /* Vista */
10140     { WM_DESTROY, sent },
10141     { WM_NCDESTROY, sent },
10142     { 0 }
10143 };
10144
10145 static const struct message WmStopQuitSeq[] = {
10146     { WM_DWMNCRENDERINGCHANGED, posted|optional },
10147     { WM_CLOSE, posted },
10148     { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
10149     { 0 }
10150 };
10151
10152 static void test_quit_message(void)
10153 {
10154     MSG msg;
10155     BOOL ret;
10156
10157     /* test using PostQuitMessage */
10158     flush_events();
10159     PostQuitMessage(0xbeef);
10160
10161     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10162     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10163     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10164     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10165
10166     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10167     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10168
10169     ret = GetMessage(&msg, NULL, 0, 0);
10170     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10171     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10172
10173     /* note: WM_QUIT message received after WM_USER message */
10174     ret = GetMessage(&msg, NULL, 0, 0);
10175     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10176     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10177     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10178
10179     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10180     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10181
10182     /* now test with PostThreadMessage - different behaviour! */
10183     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10184
10185     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10186     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10187     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10188     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10189
10190     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10191     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10192
10193     /* note: we receive the WM_QUIT message first this time */
10194     ret = GetMessage(&msg, NULL, 0, 0);
10195     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10196     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10197     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10198
10199     ret = GetMessage(&msg, NULL, 0, 0);
10200     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10201     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10202
10203     flush_events();
10204     flush_sequence();
10205     ret = DialogBoxParam(GetModuleHandle(0), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
10206     ok(ret == 1, "expected 1, got %d\n", ret);
10207     ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
10208     memset(&msg, 0xab, sizeof(msg));
10209     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10210     ok(ret, "PeekMessage failed\n");
10211     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10212     ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
10213     ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
10214
10215     /* Check what happens to a WM_QUIT message posted to a window that gets
10216      * destroyed.
10217      */
10218     CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
10219                     0, 0, 100, 100, NULL, NULL, NULL, NULL);
10220     flush_sequence();
10221     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10222     {
10223         struct recvd_message rmsg;
10224         rmsg.hwnd = msg.hwnd;
10225         rmsg.message = msg.message;
10226         rmsg.flags = posted|wparam|lparam;
10227         rmsg.wParam = msg.wParam;
10228         rmsg.lParam = msg.lParam;
10229         rmsg.descr = "stop/quit";
10230         if (msg.message == WM_QUIT)
10231             /* The hwnd can only be checked here */
10232             ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
10233         add_message(&rmsg);
10234         DispatchMessage(&msg);
10235     }
10236     ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
10237 }
10238
10239 static const struct message WmMouseHoverSeq[] = {
10240     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10241     { WM_MOUSEACTIVATE, sent|optional },
10242     { WM_TIMER, sent|optional }, /* XP sends it */
10243     { WM_SYSTIMER, sent },
10244     { WM_MOUSEHOVER, sent|wparam, 0 },
10245     { 0 }
10246 };
10247
10248 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10249 {
10250     MSG msg;
10251     DWORD start_ticks, end_ticks;
10252
10253     start_ticks = GetTickCount();
10254     /* add some deviation (50%) to cover not expected delays */
10255     start_ticks += timeout / 2;
10256
10257     do
10258     {
10259         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10260         {
10261             /* Timer proc messages are not dispatched to the window proc,
10262              * and therefore not logged.
10263              */
10264             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10265             {
10266                 struct recvd_message s_msg;
10267
10268                 s_msg.hwnd = msg.hwnd;
10269                 s_msg.message = msg.message;
10270                 s_msg.flags = sent|wparam|lparam;
10271                 s_msg.wParam = msg.wParam;
10272                 s_msg.lParam = msg.lParam;
10273                 s_msg.descr = "msg_loop";
10274                 add_message(&s_msg);
10275             }
10276             DispatchMessage(&msg);
10277         }
10278
10279         end_ticks = GetTickCount();
10280
10281         /* inject WM_MOUSEMOVE to see how it changes tracking */
10282         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10283         {
10284             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10285             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10286
10287             inject_mouse_move = FALSE;
10288         }
10289     } while (start_ticks + timeout >= end_ticks);
10290 }
10291
10292 static void test_TrackMouseEvent(void)
10293 {
10294     TRACKMOUSEEVENT tme;
10295     BOOL ret;
10296     HWND hwnd, hchild;
10297     RECT rc_parent, rc_child;
10298     UINT default_hover_time, hover_width = 0, hover_height = 0;
10299
10300 #define track_hover(track_hwnd, track_hover_time) \
10301     tme.cbSize = sizeof(tme); \
10302     tme.dwFlags = TME_HOVER; \
10303     tme.hwndTrack = track_hwnd; \
10304     tme.dwHoverTime = track_hover_time; \
10305     SetLastError(0xdeadbeef); \
10306     ret = pTrackMouseEvent(&tme); \
10307     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10308
10309 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10310     tme.cbSize = sizeof(tme); \
10311     tme.dwFlags = TME_QUERY; \
10312     tme.hwndTrack = (HWND)0xdeadbeef; \
10313     tme.dwHoverTime = 0xdeadbeef; \
10314     SetLastError(0xdeadbeef); \
10315     ret = pTrackMouseEvent(&tme); \
10316     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10317     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10318     ok(tme.dwFlags == (expected_track_flags), \
10319        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10320     ok(tme.hwndTrack == (expected_track_hwnd), \
10321        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10322     ok(tme.dwHoverTime == (expected_hover_time), \
10323        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10324
10325 #define track_hover_cancel(track_hwnd) \
10326     tme.cbSize = sizeof(tme); \
10327     tme.dwFlags = TME_HOVER | TME_CANCEL; \
10328     tme.hwndTrack = track_hwnd; \
10329     tme.dwHoverTime = 0xdeadbeef; \
10330     SetLastError(0xdeadbeef); \
10331     ret = pTrackMouseEvent(&tme); \
10332     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10333
10334     default_hover_time = 0xdeadbeef;
10335     SetLastError(0xdeadbeef);
10336     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10337     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10338        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10339     if (!ret) default_hover_time = 400;
10340     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10341
10342     SetLastError(0xdeadbeef);
10343     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10344     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10345        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10346     if (!ret) hover_width = 4;
10347     SetLastError(0xdeadbeef);
10348     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10349     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10350        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10351     if (!ret) hover_height = 4;
10352     trace("hover rect is %u x %d\n", hover_width, hover_height);
10353
10354     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
10355                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10356                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10357                           NULL, NULL, 0);
10358     assert(hwnd);
10359
10360     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
10361                           WS_CHILD | WS_BORDER | WS_VISIBLE,
10362                           50, 50, 200, 200, hwnd,
10363                           NULL, NULL, 0);
10364     assert(hchild);
10365
10366     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10367     flush_events();
10368     flush_sequence();
10369
10370     tme.cbSize = 0;
10371     tme.dwFlags = TME_QUERY;
10372     tme.hwndTrack = (HWND)0xdeadbeef;
10373     tme.dwHoverTime = 0xdeadbeef;
10374     SetLastError(0xdeadbeef);
10375     ret = pTrackMouseEvent(&tme);
10376     ok(!ret, "TrackMouseEvent should fail\n");
10377     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10378        "not expected error %u\n", GetLastError());
10379
10380     tme.cbSize = sizeof(tme);
10381     tme.dwFlags = TME_HOVER;
10382     tme.hwndTrack = (HWND)0xdeadbeef;
10383     tme.dwHoverTime = 0xdeadbeef;
10384     SetLastError(0xdeadbeef);
10385     ret = pTrackMouseEvent(&tme);
10386     ok(!ret, "TrackMouseEvent should fail\n");
10387     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10388        "not expected error %u\n", GetLastError());
10389
10390     tme.cbSize = sizeof(tme);
10391     tme.dwFlags = TME_HOVER | TME_CANCEL;
10392     tme.hwndTrack = (HWND)0xdeadbeef;
10393     tme.dwHoverTime = 0xdeadbeef;
10394     SetLastError(0xdeadbeef);
10395     ret = pTrackMouseEvent(&tme);
10396     ok(!ret, "TrackMouseEvent should fail\n");
10397     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10398        "not expected error %u\n", GetLastError());
10399
10400     GetWindowRect(hwnd, &rc_parent);
10401     GetWindowRect(hchild, &rc_child);
10402     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10403
10404     /* Process messages so that the system updates its internal current
10405      * window and hittest, otherwise TrackMouseEvent calls don't have any
10406      * effect.
10407      */
10408     flush_events();
10409     flush_sequence();
10410
10411     track_query(0, NULL, 0);
10412     track_hover(hchild, 0);
10413     track_query(0, NULL, 0);
10414
10415     flush_events();
10416     flush_sequence();
10417
10418     track_hover(hwnd, 0);
10419     tme.cbSize = sizeof(tme);
10420     tme.dwFlags = TME_QUERY;
10421     tme.hwndTrack = (HWND)0xdeadbeef;
10422     tme.dwHoverTime = 0xdeadbeef;
10423     SetLastError(0xdeadbeef);
10424     ret = pTrackMouseEvent(&tme);
10425     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10426     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10427     if (!tme.dwFlags)
10428     {
10429         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10430         DestroyWindow( hwnd );
10431         return;
10432     }
10433     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10434     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10435     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10436        tme.dwHoverTime, default_hover_time);
10437
10438     pump_msg_loop_timeout(default_hover_time, FALSE);
10439     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10440
10441     track_query(0, NULL, 0);
10442
10443     track_hover(hwnd, HOVER_DEFAULT);
10444     track_query(TME_HOVER, hwnd, default_hover_time);
10445
10446     Sleep(default_hover_time / 2);
10447     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10448     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10449
10450     track_query(TME_HOVER, hwnd, default_hover_time);
10451
10452     pump_msg_loop_timeout(default_hover_time, FALSE);
10453     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10454
10455     track_query(0, NULL, 0);
10456
10457     track_hover(hwnd, HOVER_DEFAULT);
10458     track_query(TME_HOVER, hwnd, default_hover_time);
10459
10460     pump_msg_loop_timeout(default_hover_time, TRUE);
10461     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10462
10463     track_query(0, NULL, 0);
10464
10465     track_hover(hwnd, HOVER_DEFAULT);
10466     track_query(TME_HOVER, hwnd, default_hover_time);
10467     track_hover_cancel(hwnd);
10468
10469     DestroyWindow(hwnd);
10470
10471 #undef track_hover
10472 #undef track_query
10473 #undef track_hover_cancel
10474 }
10475
10476
10477 static const struct message WmSetWindowRgn[] = {
10478     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10479     { WM_NCCALCSIZE, sent|wparam, 1 },
10480     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10481     { WM_GETTEXT, sent|defwinproc|optional },
10482     { WM_ERASEBKGND, sent|optional },
10483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10484     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10485     { 0 }
10486 };
10487
10488 static const struct message WmSetWindowRgn_no_redraw[] = {
10489     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10490     { WM_NCCALCSIZE, sent|wparam, 1 },
10491     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10492     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10493     { 0 }
10494 };
10495
10496 static const struct message WmSetWindowRgn_clear[] = {
10497     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10498     { WM_NCCALCSIZE, sent|wparam, 1 },
10499     { WM_NCPAINT, sent|optional },
10500     { WM_GETTEXT, sent|defwinproc|optional },
10501     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10502     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10503     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10504     { WM_NCPAINT, sent|optional },
10505     { WM_GETTEXT, sent|defwinproc|optional },
10506     { WM_ERASEBKGND, sent|optional },
10507     { WM_WINDOWPOSCHANGING, sent|optional },
10508     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10509     { WM_NCPAINT, sent|optional },
10510     { WM_GETTEXT, sent|defwinproc|optional },
10511     { WM_ERASEBKGND, sent|optional },
10512     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10513     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10514     { WM_NCPAINT, sent|optional },
10515     { WM_GETTEXT, sent|defwinproc|optional },
10516     { WM_ERASEBKGND, sent|optional },
10517     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10518     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10519     { 0 }
10520 };
10521
10522 static void test_SetWindowRgn(void)
10523 {
10524     HRGN hrgn;
10525     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10526                                 100, 100, 200, 200, 0, 0, 0, NULL);
10527     ok( hwnd != 0, "Failed to create overlapped window\n" );
10528
10529     ShowWindow( hwnd, SW_SHOW );
10530     UpdateWindow( hwnd );
10531     flush_events();
10532     flush_sequence();
10533
10534     trace("testing SetWindowRgn\n");
10535     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10536     SetWindowRgn( hwnd, hrgn, TRUE );
10537     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10538
10539     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10540     SetWindowRgn( hwnd, hrgn, FALSE );
10541     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10542
10543     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10544     SetWindowRgn( hwnd, hrgn, TRUE );
10545     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10546
10547     SetWindowRgn( hwnd, 0, TRUE );
10548     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10549
10550     DestroyWindow( hwnd );
10551 }
10552
10553 /*************************** ShowWindow() test ******************************/
10554 static const struct message WmShowNormal[] = {
10555     { WM_SHOWWINDOW, sent|wparam, 1 },
10556     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10557     { HCBT_ACTIVATE, hook },
10558     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10559     { HCBT_SETFOCUS, hook },
10560     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10561     { 0 }
10562 };
10563 static const struct message WmShow[] = {
10564     { WM_SHOWWINDOW, sent|wparam, 1 },
10565     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10566     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10567     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10568     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10569     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10570     { 0 }
10571 };
10572 static const struct message WmShowNoActivate_1[] = {
10573     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10574     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10575     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10576     { WM_MOVE, sent|defwinproc|optional },
10577     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10578     { 0 }
10579 };
10580 static const struct message WmShowNoActivate_2[] = {
10581     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10582     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10583     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10584     { WM_MOVE, sent|defwinproc },
10585     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10586     { HCBT_SETFOCUS, hook|optional },
10587     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10588     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10589     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10590     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10591     { 0 }
10592 };
10593 static const struct message WmShowNA_1[] = {
10594     { WM_SHOWWINDOW, sent|wparam, 1 },
10595     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10596     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10597     { 0 }
10598 };
10599 static const struct message WmShowNA_2[] = {
10600     { WM_SHOWWINDOW, sent|wparam, 1 },
10601     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10602     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10603     { 0 }
10604 };
10605 static const struct message WmRestore_1[] = {
10606     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10607     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10608     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10609     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10610     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10611     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10612     { WM_MOVE, sent|defwinproc },
10613     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10614     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10615     { 0 }
10616 };
10617 static const struct message WmRestore_2[] = {
10618     { WM_SHOWWINDOW, sent|wparam, 1 },
10619     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10620     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10621     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10622     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10623     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10624     { 0 }
10625 };
10626 static const struct message WmRestore_3[] = {
10627     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10628     { WM_GETMINMAXINFO, sent },
10629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10630     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10631     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10632     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10633     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10634     { WM_MOVE, sent|defwinproc },
10635     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10636     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10637     { 0 }
10638 };
10639 static const struct message WmRestore_4[] = {
10640     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10641     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10642     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10643     { WM_MOVE, sent|defwinproc|optional },
10644     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10645     { 0 }
10646 };
10647 static const struct message WmRestore_5[] = {
10648     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10649     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10650     { HCBT_ACTIVATE, hook|optional },
10651     { HCBT_SETFOCUS, hook|optional },
10652     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10653     { WM_MOVE, sent|defwinproc|optional },
10654     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10655     { 0 }
10656 };
10657 static const struct message WmHide_1[] = {
10658     { WM_SHOWWINDOW, sent|wparam, 0 },
10659     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10660     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10661     { HCBT_ACTIVATE, hook|optional },
10662     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10663     { 0 }
10664 };
10665 static const struct message WmHide_2[] = {
10666     { WM_SHOWWINDOW, sent|wparam, 0 },
10667     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10668     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10669     { HCBT_ACTIVATE, hook|optional },
10670     { 0 }
10671 };
10672 static const struct message WmHide_3[] = {
10673     { WM_SHOWWINDOW, sent|wparam, 0 },
10674     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10675     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10676     { HCBT_SETFOCUS, hook|optional },
10677     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10678     { 0 }
10679 };
10680 static const struct message WmShowMinimized_1[] = {
10681     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10682     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10683     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10684     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10685     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10686     { WM_MOVE, sent|defwinproc },
10687     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10688     { 0 }
10689 };
10690 static const struct message WmMinimize_1[] = {
10691     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10692     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10693     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10694     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10695     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10696     { WM_MOVE, sent|defwinproc },
10697     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10698     { 0 }
10699 };
10700 static const struct message WmMinimize_2[] = {
10701     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10702     { HCBT_SETFOCUS, hook|optional },
10703     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10705     { WM_MOVE, sent|defwinproc },
10706     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10707     { 0 }
10708 };
10709 static const struct message WmMinimize_3[] = {
10710     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10711     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10712     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10713     { WM_MOVE, sent|defwinproc },
10714     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10715     { 0 }
10716 };
10717 static const struct message WmShowMinNoActivate[] = {
10718     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10719     { WM_WINDOWPOSCHANGING, sent },
10720     { WM_WINDOWPOSCHANGED, sent },
10721     { WM_MOVE, sent|defwinproc|optional },
10722     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10723     { 0 }
10724 };
10725 static const struct message WmMinMax_1[] = {
10726     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10727     { 0 }
10728 };
10729 static const struct message WmMinMax_2[] = {
10730     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10731     { WM_GETMINMAXINFO, sent|optional },
10732     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10733     { HCBT_ACTIVATE, hook|optional },
10734     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10735     { HCBT_SETFOCUS, hook|optional },
10736     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10737     { WM_MOVE, sent|defwinproc|optional },
10738     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10739     { HCBT_SETFOCUS, hook|optional },
10740     { 0 }
10741 };
10742 static const struct message WmMinMax_3[] = {
10743     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10744     { HCBT_SETFOCUS, hook|optional },
10745     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10746     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10747     { WM_MOVE, sent|defwinproc|optional },
10748     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10749     { 0 }
10750 };
10751 static const struct message WmMinMax_4[] = {
10752     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10753     { 0 }
10754 };
10755 static const struct message WmShowMaximized_1[] = {
10756     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10757     { WM_GETMINMAXINFO, sent },
10758     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10759     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10760     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10761     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10762     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10763     { WM_MOVE, sent|defwinproc },
10764     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10765     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10766     { 0 }
10767 };
10768 static const struct message WmShowMaximized_2[] = {
10769     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10770     { WM_GETMINMAXINFO, sent },
10771     { WM_WINDOWPOSCHANGING, sent|optional },
10772     { HCBT_ACTIVATE, hook|optional },
10773     { WM_WINDOWPOSCHANGED, sent|optional },
10774     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10775     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10776     { WM_WINDOWPOSCHANGING, sent|optional },
10777     { HCBT_SETFOCUS, hook|optional },
10778     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10779     { WM_MOVE, sent|defwinproc },
10780     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10781     { HCBT_SETFOCUS, hook|optional },
10782     { 0 }
10783 };
10784 static const struct message WmShowMaximized_3[] = {
10785     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10786     { WM_GETMINMAXINFO, sent|optional },
10787     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10788     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10789     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10790     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10791     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10792     { WM_MOVE, sent|defwinproc|optional },
10793     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10794     { 0 }
10795 };
10796
10797 static void test_ShowWindow(void)
10798 {
10799     /* ShowWindow commands in random order */
10800     static const struct
10801     {
10802         INT cmd; /* ShowWindow command */
10803         LPARAM ret; /* ShowWindow return value */
10804         DWORD style; /* window style after the command */
10805         const struct message *msg; /* message sequence the command produces */
10806         INT wp_cmd, wp_flags; /* window placement after the command */
10807         POINT wp_min, wp_max; /* window placement after the command */
10808         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10809     } sw[] =
10810     {
10811 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
10812            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10813 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
10814            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10815 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
10816            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10817 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10818            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10819 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
10820            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10821 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
10822            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10823 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
10824            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10825 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10826            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10827 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
10828            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10829 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10830            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10831 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
10832            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10833 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
10834            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10835 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
10836            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10837 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10838            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10839 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
10840            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10841 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10842            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10843 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
10844            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10845 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10846            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10847 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10848            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10849 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10850            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10851 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10852            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10853 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
10854            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
10855 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
10856            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10857 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10858            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10859 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10860            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10861 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
10862            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10863 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
10864            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10865 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10866            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10867 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10868            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10869 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
10870            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10871 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10872            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10873 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
10874            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10875 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10876            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10877 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
10878            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10879 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
10880            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10881 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10882            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10883 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
10884            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10885 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10886            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10887 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10888            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10889 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
10890            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10891 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10892            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10893 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
10894            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10895 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10896            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10897 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10898            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10899 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10900            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10901 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
10902            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10903 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
10904            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10905 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
10906            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10907 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
10908            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10909 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10910            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10911 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10912            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10913 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
10914            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10915 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10916            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10917 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
10918            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10919 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10920            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10921 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
10922            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10923 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10924            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
10925     };
10926     HWND hwnd;
10927     DWORD style;
10928     LPARAM ret;
10929     INT i;
10930     WINDOWPLACEMENT wp;
10931     RECT win_rc, work_rc = {0, 0, 0, 0};
10932
10933 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10934     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10935                           120, 120, 90, 90,
10936                           0, 0, 0, NULL);
10937     assert(hwnd);
10938
10939     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10940     ok(style == 0, "expected style 0, got %08x\n", style);
10941
10942     flush_events();
10943     flush_sequence();
10944
10945     if (pGetMonitorInfoA && pMonitorFromPoint)
10946     {
10947         HMONITOR hmon;
10948         MONITORINFO mi;
10949         POINT pt = {0, 0};
10950
10951         SetLastError(0xdeadbeef);
10952         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
10953         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
10954
10955         mi.cbSize = sizeof(mi);
10956         SetLastError(0xdeadbeef);
10957         ret = pGetMonitorInfoA(hmon, &mi);
10958         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
10959         trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
10960             mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
10961             mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
10962         work_rc = mi.rcWork;
10963     }
10964
10965     GetWindowRect(hwnd, &win_rc);
10966     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
10967
10968     wp.length = sizeof(wp);
10969     SetLastError(0xdeadbeaf);
10970     ret = GetWindowPlacement(hwnd, &wp);
10971     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
10972     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
10973     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
10974     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
10975        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
10976     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
10977        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
10978     if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
10979     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10980        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10981         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10982         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10983         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10984     else
10985     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10986        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10987         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10988         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10989         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10990
10991     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10992     {
10993         static const char * const sw_cmd_name[13] =
10994         {
10995             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10996             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10997             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10998             "SW_NORMALNA" /* 0xCC */
10999         };
11000         char comment[64];
11001         INT idx; /* index into the above array of names */
11002
11003         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
11004
11005         style = GetWindowLong(hwnd, GWL_STYLE);
11006         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
11007         ret = ShowWindow(hwnd, sw[i].cmd);
11008         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
11009         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
11010         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
11011
11012         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
11013         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
11014
11015         wp.length = sizeof(wp);
11016         SetLastError(0xdeadbeaf);
11017         ret = GetWindowPlacement(hwnd, &wp);
11018         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
11019         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
11020         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
11021
11022         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
11023         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
11024             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
11025         {
11026             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
11027                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
11028                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11029         }
11030         else
11031         {
11032             if (wp.ptMinPosition.x != sw[i].wp_min.x || wp.ptMinPosition.y != sw[i].wp_min.y)
11033             todo_wine
11034             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
11035                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11036             else
11037             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
11038                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
11039         }
11040
11041         if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
11042         todo_wine
11043         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11044            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11045         else
11046         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11047            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11048
11049 if (0) /* FIXME: Wine behaves completely different here */
11050         ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11051            "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11052             win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11053             wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11054             wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11055
11056         flush_events();
11057         flush_sequence();
11058     }
11059
11060     DestroyWindow(hwnd);
11061 }
11062
11063 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11064 {
11065     struct recvd_message msg;
11066
11067     if (ignore_message( message )) return 0;
11068
11069     msg.hwnd = hwnd;
11070     msg.message = message;
11071     msg.flags = sent|wparam|lparam;
11072     msg.wParam = wParam;
11073     msg.lParam = lParam;
11074     msg.descr = "dialog";
11075     add_message(&msg);
11076
11077     /* calling DefDlgProc leads to a recursion under XP */
11078
11079     switch (message)
11080     {
11081     case WM_INITDIALOG:
11082     case WM_GETDLGCODE:
11083         return 0;
11084     }
11085     return 1;
11086 }
11087
11088 static const struct message WmDefDlgSetFocus_1[] = {
11089     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11090     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11091     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11092     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11093     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11094     { HCBT_SETFOCUS, hook },
11095     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11096     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11097     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11098     { WM_SETFOCUS, sent|wparam, 0 },
11099     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11100     { WM_CTLCOLOREDIT, sent },
11101     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11102     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11103     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11104     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11105     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
11106     { 0 }
11107 };
11108 static const struct message WmDefDlgSetFocus_2[] = {
11109     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11110     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11111     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11112     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11113     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11114     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11115     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
11116     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11117     { 0 }
11118 };
11119 /* Creation of a dialog */
11120 static const struct message WmCreateDialogParamSeq_1[] = {
11121     { HCBT_CREATEWND, hook },
11122     { WM_NCCREATE, sent },
11123     { WM_NCCALCSIZE, sent|wparam, 0 },
11124     { WM_CREATE, sent },
11125     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11126     { WM_SIZE, sent|wparam, SIZE_RESTORED },
11127     { WM_MOVE, sent },
11128     { WM_SETFONT, sent },
11129     { WM_INITDIALOG, sent },
11130     { WM_CHANGEUISTATE, sent|optional },
11131     { 0 }
11132 };
11133 /* Creation of a dialog */
11134 static const struct message WmCreateDialogParamSeq_2[] = {
11135     { HCBT_CREATEWND, hook },
11136     { WM_NCCREATE, sent },
11137     { WM_NCCALCSIZE, sent|wparam, 0 },
11138     { WM_CREATE, sent },
11139     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11140     { WM_SIZE, sent|wparam, SIZE_RESTORED },
11141     { WM_MOVE, sent },
11142     { WM_CHANGEUISTATE, sent|optional },
11143     { 0 }
11144 };
11145
11146 static void test_dialog_messages(void)
11147 {
11148     WNDCLASS cls;
11149     HWND hdlg, hedit1, hedit2, hfocus;
11150     LRESULT ret;
11151
11152 #define set_selection(hctl, start, end) \
11153     ret = SendMessage(hctl, EM_SETSEL, start, end); \
11154     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
11155
11156 #define check_selection(hctl, start, end) \
11157     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
11158     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11159
11160     subclass_edit();
11161
11162     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11163                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11164                           0, 0, 100, 100, 0, 0, 0, NULL);
11165     ok(hdlg != 0, "Failed to create custom dialog window\n");
11166
11167     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
11168                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11169                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11170     ok(hedit1 != 0, "Failed to create edit control\n");
11171     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
11172                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11173                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11174     ok(hedit2 != 0, "Failed to create edit control\n");
11175
11176     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11177     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11178
11179     hfocus = GetFocus();
11180     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11181
11182     SetFocus(hedit2);
11183     hfocus = GetFocus();
11184     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11185
11186     check_selection(hedit1, 0, 0);
11187     check_selection(hedit2, 0, 0);
11188
11189     set_selection(hedit2, 0, -1);
11190     check_selection(hedit2, 0, 3);
11191
11192     SetFocus(0);
11193     hfocus = GetFocus();
11194     ok(hfocus == 0, "wrong focus %p\n", hfocus);
11195
11196     flush_sequence();
11197     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11198     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11199     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11200
11201     hfocus = GetFocus();
11202     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11203
11204     check_selection(hedit1, 0, 5);
11205     check_selection(hedit2, 0, 3);
11206
11207     flush_sequence();
11208     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11209     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11210     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11211
11212     hfocus = GetFocus();
11213     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11214
11215     check_selection(hedit1, 0, 5);
11216     check_selection(hedit2, 0, 3);
11217
11218     EndDialog(hdlg, 0);
11219     DestroyWindow(hedit1);
11220     DestroyWindow(hedit2);
11221     DestroyWindow(hdlg);
11222     flush_sequence();
11223
11224 #undef set_selection
11225 #undef check_selection
11226
11227     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
11228     cls.lpszClassName = "MyDialogClass";
11229     cls.hInstance = GetModuleHandle(0);
11230     /* need a cast since a dlgproc is used as a wndproc */
11231     cls.lpfnWndProc = test_dlg_proc;
11232     if (!RegisterClass(&cls)) assert(0);
11233
11234     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11235     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11236     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11237     EndDialog(hdlg, 0);
11238     DestroyWindow(hdlg);
11239     flush_sequence();
11240
11241     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11242     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11243     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11244     EndDialog(hdlg, 0);
11245     DestroyWindow(hdlg);
11246     flush_sequence();
11247
11248     UnregisterClass(cls.lpszClassName, cls.hInstance);
11249 }
11250
11251 static void test_EndDialog(void)
11252 {
11253     HWND hparent, hother, hactive, hdlg;
11254     WNDCLASS cls;
11255
11256     hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
11257                               WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
11258                               100, 100, 200, 200, 0, 0, 0, NULL);
11259     ok (hparent != 0, "Failed to create parent window\n");
11260
11261     hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
11262                               WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11263                               100, 100, 200, 200, 0, 0, 0, NULL);
11264     ok (hother != 0, "Failed to create parent window\n");
11265
11266     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
11267     cls.lpszClassName = "MyDialogClass";
11268     cls.hInstance = GetModuleHandle(0);
11269     /* need a cast since a dlgproc is used as a wndproc */
11270     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
11271     if (!RegisterClass(&cls)) assert(0);
11272
11273     flush_sequence();
11274     SetForegroundWindow(hother);
11275     hactive = GetForegroundWindow();
11276     ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
11277
11278     /* create a dialog where the parent is disabled, this parent should still
11279        receive the focus when the dialog exits (even though "normally" a
11280        disabled window should not receive the focus) */
11281     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
11282     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11283     SetForegroundWindow(hdlg);
11284     hactive = GetForegroundWindow();
11285     ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
11286     EndDialog(hdlg, 0);
11287     hactive = GetForegroundWindow();
11288     ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
11289     DestroyWindow(hdlg);
11290     flush_sequence();
11291
11292     DestroyWindow( hother );
11293     DestroyWindow( hparent );
11294     UnregisterClass(cls.lpszClassName, cls.hInstance);
11295 }
11296
11297 static void test_nullCallback(void)
11298 {
11299     HWND hwnd;
11300
11301     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11302                            100, 100, 200, 200, 0, 0, 0, NULL);
11303     ok (hwnd != 0, "Failed to create overlapped window\n");
11304
11305     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11306     flush_events();
11307     DestroyWindow(hwnd);
11308 }
11309
11310 /* SetActiveWindow( 0 ) hwnd visible */
11311 static const struct message SetActiveWindowSeq0[] =
11312 {
11313     { HCBT_ACTIVATE, hook|optional },
11314     { WM_NCACTIVATE, sent|wparam, 0 },
11315     { WM_GETTEXT, sent|defwinproc|optional },
11316     { WM_ACTIVATE, sent|wparam, 0 },
11317     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11318     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11319     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11320     { WM_KILLFOCUS, sent|optional },
11321     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11322     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11323     { WM_NCACTIVATE, sent|wparam|optional, 1 },
11324     { WM_GETTEXT, sent|defwinproc|optional },
11325     { WM_ACTIVATE, sent|wparam|optional, 1 },
11326     { HCBT_SETFOCUS, hook|optional },
11327     { WM_KILLFOCUS, sent|defwinproc|optional },
11328     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11329     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11330     { WM_IME_SETCONTEXT, sent|optional },
11331     { WM_IME_SETCONTEXT, sent|optional },
11332     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11333     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11334     { WM_SETFOCUS, sent|defwinproc|optional },
11335     { WM_GETTEXT, sent|optional },
11336     { 0 }
11337 };
11338 /* SetActiveWindow( hwnd ) hwnd visible */
11339 static const struct message SetActiveWindowSeq1[] =
11340 {
11341     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11342     { 0 }
11343 };
11344 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11345 static const struct message SetActiveWindowSeq2[] =
11346 {
11347     { HCBT_ACTIVATE, hook },
11348     { WM_NCACTIVATE, sent|wparam, 0 },
11349     { WM_GETTEXT, sent|defwinproc|optional },
11350     { WM_ACTIVATE, sent|wparam, 0 },
11351     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11352     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11353     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11354     { WM_NCPAINT, sent|optional },
11355     { WM_GETTEXT, sent|defwinproc|optional },
11356     { WM_ERASEBKGND, sent|optional },
11357     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11358     { WM_NCACTIVATE, sent|wparam, 1 },
11359     { WM_GETTEXT, sent|defwinproc|optional },
11360     { WM_ACTIVATE, sent|wparam, 1 },
11361     { HCBT_SETFOCUS, hook },
11362     { WM_KILLFOCUS, sent|defwinproc },
11363     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11364     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11365     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11366     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11367     { WM_SETFOCUS, sent|defwinproc },
11368     { WM_GETTEXT, sent|optional },
11369     { 0 }
11370 };
11371
11372 /* SetActiveWindow( hwnd ) hwnd not visible */
11373 static const struct message SetActiveWindowSeq3[] =
11374 {
11375     { HCBT_ACTIVATE, hook },
11376     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11377     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11378     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11379     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11380     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11381     { WM_ACTIVATEAPP, sent|wparam, 1 },
11382     { WM_ACTIVATEAPP, sent|wparam, 1 },
11383     { WM_NCACTIVATE, sent|wparam, 1 },
11384     { WM_ACTIVATE, sent|wparam, 1 },
11385     { HCBT_SETFOCUS, hook },
11386     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11387     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11388     { WM_SETFOCUS, sent|defwinproc },
11389     { 0 }
11390 };
11391 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11392 static const struct message SetActiveWindowSeq4[] =
11393 {
11394     { HCBT_ACTIVATE, hook },
11395     { WM_NCACTIVATE, sent|wparam, 0 },
11396     { WM_GETTEXT, sent|defwinproc|optional },
11397     { WM_ACTIVATE, sent|wparam, 0 },
11398     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11399     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11400     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11401     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11402     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11403     { WM_NCACTIVATE, sent|wparam, 1 },
11404     { WM_GETTEXT, sent|defwinproc|optional },
11405     { WM_ACTIVATE, sent|wparam, 1 },
11406     { HCBT_SETFOCUS, hook },
11407     { WM_KILLFOCUS, sent|defwinproc },
11408     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11409     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11410     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11411     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11412     { WM_SETFOCUS, sent|defwinproc },
11413     { 0 }
11414 };
11415
11416
11417 static void test_SetActiveWindow(void)
11418 {
11419     HWND hwnd, popup, ret;
11420
11421     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11422                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11423                            100, 100, 200, 200, 0, 0, 0, NULL);
11424
11425     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11426                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11427                            100, 100, 200, 200, hwnd, 0, 0, NULL);
11428
11429     ok(hwnd != 0, "Failed to create overlapped window\n");
11430     ok(popup != 0, "Failed to create popup window\n");
11431     SetForegroundWindow( popup );
11432     flush_sequence();
11433
11434     trace("SetActiveWindow(0)\n");
11435     ret = SetActiveWindow(0);
11436     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11437     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11438     flush_sequence();
11439
11440     trace("SetActiveWindow(hwnd), hwnd visible\n");
11441     ret = SetActiveWindow(hwnd);
11442     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11443     flush_sequence();
11444
11445     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11446     ret = SetActiveWindow(popup);
11447     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11448     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11449     flush_sequence();
11450
11451     ShowWindow(hwnd, SW_HIDE);
11452     ShowWindow(popup, SW_HIDE);
11453     flush_sequence();
11454
11455     trace("SetActiveWindow(hwnd), hwnd not visible\n");
11456     ret = SetActiveWindow(hwnd);
11457     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11458     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11459     flush_sequence();
11460
11461     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11462     ret = SetActiveWindow(popup);
11463     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11464     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11465     flush_sequence();
11466
11467     trace("done\n");
11468
11469     DestroyWindow(hwnd);
11470 }
11471
11472 static const struct message SetForegroundWindowSeq[] =
11473 {
11474     { WM_NCACTIVATE, sent|wparam, 0 },
11475     { WM_GETTEXT, sent|defwinproc|optional },
11476     { WM_ACTIVATE, sent|wparam, 0 },
11477     { WM_ACTIVATEAPP, sent|wparam, 0 },
11478     { WM_KILLFOCUS, sent },
11479     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11480     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11481     { 0 }
11482 };
11483
11484 static void test_SetForegroundWindow(void)
11485 {
11486     HWND hwnd;
11487
11488     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11489                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11490                            100, 100, 200, 200, 0, 0, 0, NULL);
11491     ok (hwnd != 0, "Failed to create overlapped window\n");
11492     SetForegroundWindow( hwnd );
11493     flush_sequence();
11494
11495     trace("SetForegroundWindow( 0 )\n");
11496     SetForegroundWindow( 0 );
11497     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11498     trace("SetForegroundWindow( GetDesktopWindow() )\n");
11499     SetForegroundWindow( GetDesktopWindow() );
11500     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11501                                         "foreground top level window", FALSE);
11502     trace("done\n");
11503
11504     DestroyWindow(hwnd);
11505 }
11506
11507 static void test_dbcs_wm_char(void)
11508 {
11509     BYTE dbch[2];
11510     WCHAR wch, bad_wch;
11511     HWND hwnd, hwnd2;
11512     MSG msg;
11513     DWORD time;
11514     POINT pt;
11515     DWORD_PTR res;
11516     CPINFOEXA cpinfo;
11517     UINT i, j, k;
11518     struct message wmCharSeq[2];
11519     BOOL ret;
11520
11521     if (!pGetCPInfoExA)
11522     {
11523         win_skip("GetCPInfoExA is not available\n");
11524         return;
11525     }
11526
11527     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11528     if (cpinfo.MaxCharSize != 2)
11529     {
11530         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11531         return;
11532     }
11533
11534     dbch[0] = dbch[1] = 0;
11535     wch = 0;
11536     bad_wch = cpinfo.UnicodeDefaultChar;
11537     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11538         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11539             for (k = 128; k <= 255; k++)
11540             {
11541                 char str[2];
11542                 WCHAR wstr[2];
11543                 str[0] = j;
11544                 str[1] = k;
11545                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11546                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11547                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
11548                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11549                 {
11550                     dbch[0] = j;
11551                     dbch[1] = k;
11552                     wch = wstr[0];
11553                     break;
11554                 }
11555             }
11556
11557     if (!wch)
11558     {
11559         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11560         return;
11561     }
11562     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11563            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11564
11565     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11566                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11567     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11568                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11569     ok (hwnd != 0, "Failed to create overlapped window\n");
11570     ok (hwnd2 != 0, "Failed to create overlapped window\n");
11571     flush_sequence();
11572
11573     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11574     wmCharSeq[0].message = WM_CHAR;
11575     wmCharSeq[0].flags = sent|wparam;
11576     wmCharSeq[0].wParam = wch;
11577
11578     /* posted message */
11579     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11580     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11581     ok( !ret, "got message %x\n", msg.message );
11582     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11583     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11584     ok( ret, "no message\n" );
11585     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11586     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11587     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11588     ok( !ret, "got message %x\n", msg.message );
11589
11590     /* posted thread message */
11591     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11592     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11593     ok( !ret, "got message %x\n", msg.message );
11594     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11595     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11596     ok( ret, "no message\n" );
11597     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11598     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11599     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11600     ok( !ret, "got message %x\n", msg.message );
11601
11602     /* sent message */
11603     flush_sequence();
11604     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11605     ok_sequence( WmEmptySeq, "no messages", FALSE );
11606     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11607     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11608     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11609     ok( !ret, "got message %x\n", msg.message );
11610
11611     /* sent message with timeout */
11612     flush_sequence();
11613     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11614     ok_sequence( WmEmptySeq, "no messages", FALSE );
11615     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11616     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11617     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11618     ok( !ret, "got message %x\n", msg.message );
11619
11620     /* sent message with timeout and callback */
11621     flush_sequence();
11622     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11623     ok_sequence( WmEmptySeq, "no messages", FALSE );
11624     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11625     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11626     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11627     ok( !ret, "got message %x\n", msg.message );
11628
11629     /* sent message with callback */
11630     flush_sequence();
11631     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11632     ok_sequence( WmEmptySeq, "no messages", FALSE );
11633     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11634     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11635     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11636     ok( !ret, "got message %x\n", msg.message );
11637
11638     /* direct window proc call */
11639     flush_sequence();
11640     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11641     ok_sequence( WmEmptySeq, "no messages", FALSE );
11642     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11643     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11644
11645     /* dispatch message */
11646     msg.hwnd = hwnd;
11647     msg.message = WM_CHAR;
11648     msg.wParam = dbch[0];
11649     msg.lParam = 0;
11650     DispatchMessageA( &msg );
11651     ok_sequence( WmEmptySeq, "no messages", FALSE );
11652     msg.wParam = dbch[1];
11653     DispatchMessageA( &msg );
11654     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11655
11656     /* window handle is irrelevant */
11657     flush_sequence();
11658     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11659     ok_sequence( WmEmptySeq, "no messages", FALSE );
11660     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11661     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11662     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11663     ok( !ret, "got message %x\n", msg.message );
11664
11665     /* interleaved post and send */
11666     flush_sequence();
11667     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11668     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11669     ok_sequence( WmEmptySeq, "no messages", FALSE );
11670     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11671     ok( !ret, "got message %x\n", msg.message );
11672     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11673     ok_sequence( WmEmptySeq, "no messages", FALSE );
11674     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11675     ok( ret, "no message\n" );
11676     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11677     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11678     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11679     ok( !ret, "got message %x\n", msg.message );
11680     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11681     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11682     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11683     ok( !ret, "got message %x\n", msg.message );
11684
11685     /* interleaved sent message and winproc */
11686     flush_sequence();
11687     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11688     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11689     ok_sequence( WmEmptySeq, "no messages", FALSE );
11690     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11691     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11692     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11693     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11694
11695     /* interleaved winproc and dispatch */
11696     msg.hwnd = hwnd;
11697     msg.message = WM_CHAR;
11698     msg.wParam = dbch[0];
11699     msg.lParam = 0;
11700     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11701     DispatchMessageA( &msg );
11702     ok_sequence( WmEmptySeq, "no messages", FALSE );
11703     msg.wParam = dbch[1];
11704     DispatchMessageA( &msg );
11705     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11706     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11707     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11708
11709     /* interleaved sends */
11710     flush_sequence();
11711     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11712     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11713     ok_sequence( WmEmptySeq, "no messages", FALSE );
11714     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11715     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11716     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11717     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11718
11719     /* dbcs WM_CHAR */
11720     flush_sequence();
11721     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11722     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11723     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11724     ok( !ret, "got message %x\n", msg.message );
11725
11726     /* other char messages are not magic */
11727     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11728     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11729     ok( ret, "no message\n" );
11730     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11731     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11732     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11733     ok( !ret, "got message %x\n", msg.message );
11734     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11735     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11736     ok( ret, "no message\n" );
11737     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11738     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11739     ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
11740     ok( !ret, "got message %x\n", msg.message );
11741
11742     /* test retrieving messages */
11743
11744     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11745     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11746     ok( ret, "no message\n" );
11747     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11748     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11749     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11750     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11751     ok( ret, "no message\n" );
11752     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11753     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11754     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11755     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11756     ok( !ret, "got message %x\n", msg.message );
11757
11758     /* message filters */
11759     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11760     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11761     ok( ret, "no message\n" );
11762     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11763     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11764     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11765     /* message id is filtered, hwnd is not */
11766     ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
11767     ok( !ret, "no message\n" );
11768     ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
11769     ok( ret, "no message\n" );
11770     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11771     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11772     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11773     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11774     ok( !ret, "got message %x\n", msg.message );
11775
11776     /* mixing GetMessage and PostMessage */
11777     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11778     ok( GetMessageA( &msg, hwnd, 0, 0 ), "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     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11783     time = msg.time;
11784     pt = msg.pt;
11785     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11786     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
11787     ok( ret, "no message\n" );
11788     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11789     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11790     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11791     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11792     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11793     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 );
11794     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11795     ok( !ret, "got message %x\n", msg.message );
11796
11797     /* without PM_REMOVE */
11798     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11799     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
11800     ok( ret, "no message\n" );
11801     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11802     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11803     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11804     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
11805     ok( ret, "no message\n" );
11806     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11807     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11808     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11809     ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
11810     ok( ret, "no message\n" );
11811     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11812     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11813     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11814     ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
11815     ok( ret, "no message\n" );
11816     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11817     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11818     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11819     ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
11820     ok( !ret, "got message %x\n", msg.message );
11821
11822     DestroyWindow(hwnd);
11823     DestroyWindow(hwnd2);
11824 }
11825
11826 #define ID_LISTBOX 0x000f
11827
11828 static const struct message wm_lb_setcursel_0[] =
11829 {
11830     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11831     { WM_CTLCOLORLISTBOX, sent|parent },
11832     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11833     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11834     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11835     { 0 }
11836 };
11837 static const struct message wm_lb_setcursel_1[] =
11838 {
11839     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11840     { WM_CTLCOLORLISTBOX, sent|parent },
11841     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11842     { WM_CTLCOLORLISTBOX, sent|parent },
11843     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11844     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11845     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11846     { 0 }
11847 };
11848 static const struct message wm_lb_setcursel_2[] =
11849 {
11850     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11851     { WM_CTLCOLORLISTBOX, sent|parent },
11852     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11853     { WM_CTLCOLORLISTBOX, sent|parent },
11854     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11855     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11856     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11857     { 0 }
11858 };
11859 static const struct message wm_lb_click_0[] =
11860 {
11861     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11862     { HCBT_SETFOCUS, hook },
11863     { WM_KILLFOCUS, sent|parent },
11864     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11865     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11866     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11867     { WM_SETFOCUS, sent|defwinproc },
11868
11869     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11870     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11871     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11872     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11873     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11874
11875     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11876     { WM_CTLCOLORLISTBOX, sent|parent },
11877     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11878     { WM_CTLCOLORLISTBOX, sent|parent },
11879     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11880     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11881
11882     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11883     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11884
11885     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11886     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11887     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11888     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11889     { 0 }
11890 };
11891 static const struct message wm_lb_deletestring[] =
11892 {
11893     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11894     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11895     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11896     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11897     { 0 }
11898 };
11899 static const struct message wm_lb_deletestring_reset[] =
11900 {
11901     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11902     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11903     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11904     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11905     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11906     { 0 }
11907 };
11908
11909 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11910
11911 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11912
11913 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11914 {
11915     static LONG defwndproc_counter = 0;
11916     LRESULT ret;
11917     struct recvd_message msg;
11918
11919     /* do not log painting messages */
11920     if (message != WM_PAINT &&
11921         message != WM_NCPAINT &&
11922         message != WM_SYNCPAINT &&
11923         message != WM_ERASEBKGND &&
11924         message != WM_NCHITTEST &&
11925         message != WM_GETTEXT &&
11926         !ignore_message( message ))
11927     {
11928         msg.hwnd = hwnd;
11929         msg.message = message;
11930         msg.flags = sent|wparam|lparam;
11931         if (defwndproc_counter) msg.flags |= defwinproc;
11932         msg.wParam = wp;
11933         msg.lParam = lp;
11934         msg.descr = "listbox";
11935         add_message(&msg);
11936     }
11937
11938     defwndproc_counter++;
11939     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11940     defwndproc_counter--;
11941
11942     return ret;
11943 }
11944
11945 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11946                                int caret_index, int top_index, int line)
11947 {
11948     LRESULT ret;
11949
11950     /* calling an orig proc helps to avoid unnecessary message logging */
11951     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11952     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11953     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11954     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11955     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11956     ok_(__FILE__, line)(ret == caret_index ||
11957                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11958                         "expected caret index %d, got %ld\n", caret_index, ret);
11959     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11960     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11961 }
11962
11963 static void test_listbox_messages(void)
11964 {
11965     HWND parent, listbox;
11966     LRESULT ret;
11967
11968     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11969                              100, 100, 200, 200, 0, 0, 0, NULL);
11970     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11971                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11972                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11973     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11974
11975     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11976
11977     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11978     ok(ret == 0, "expected 0, got %ld\n", ret);
11979     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11980     ok(ret == 1, "expected 1, got %ld\n", ret);
11981     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11982     ok(ret == 2, "expected 2, got %ld\n", ret);
11983
11984     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11985
11986     flush_sequence();
11987
11988     log_all_parent_messages++;
11989
11990     trace("selecting item 0\n");
11991     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11992     ok(ret == 0, "expected 0, got %ld\n", ret);
11993     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11994     check_lb_state(listbox, 3, 0, 0, 0);
11995     flush_sequence();
11996
11997     trace("selecting item 1\n");
11998     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11999     ok(ret == 1, "expected 1, got %ld\n", ret);
12000     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
12001     check_lb_state(listbox, 3, 1, 1, 0);
12002
12003     trace("selecting item 2\n");
12004     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
12005     ok(ret == 2, "expected 2, got %ld\n", ret);
12006     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
12007     check_lb_state(listbox, 3, 2, 2, 0);
12008
12009     trace("clicking on item 0\n");
12010     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
12011     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12012     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
12013     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
12014     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
12015     check_lb_state(listbox, 3, 0, 0, 0);
12016     flush_sequence();
12017
12018     trace("deleting item 0\n");
12019     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12020     ok(ret == 2, "expected 2, got %ld\n", ret);
12021     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12022     check_lb_state(listbox, 2, -1, 0, 0);
12023     flush_sequence();
12024
12025     trace("deleting item 0\n");
12026     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12027     ok(ret == 1, "expected 1, got %ld\n", ret);
12028     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
12029     check_lb_state(listbox, 1, -1, 0, 0);
12030     flush_sequence();
12031
12032     trace("deleting item 0\n");
12033     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12034     ok(ret == 0, "expected 0, got %ld\n", ret);
12035     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
12036     check_lb_state(listbox, 0, -1, 0, 0);
12037     flush_sequence();
12038
12039     trace("deleting item 0\n");
12040     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
12041     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
12042     check_lb_state(listbox, 0, -1, 0, 0);
12043     flush_sequence();
12044
12045     log_all_parent_messages--;
12046
12047     DestroyWindow(listbox);
12048     DestroyWindow(parent);
12049 }
12050
12051 /*************************** Menu test ******************************/
12052 static const struct message wm_popup_menu_1[] =
12053 {
12054     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12055     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12056     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
12057     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
12058     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
12059     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
12060     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12061     { WM_INITMENU, sent|lparam, 0, 0 },
12062     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
12063     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
12064     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
12065     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
12066     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
12067     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12068     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
12069     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
12070     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12071     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12072     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12073     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
12074     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12075     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12076     { 0 }
12077 };
12078 static const struct message wm_popup_menu_2[] =
12079 {
12080     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12081     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12082     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12083     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12084     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12085     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12086     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12087     { WM_INITMENU, sent|lparam, 0, 0 },
12088     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12089     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12090     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12091     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12092     { HCBT_CREATEWND, hook },
12093     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12094                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12095     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12096     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12097     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12098     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12099     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12100     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12101     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12102     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12103     { HCBT_DESTROYWND, hook },
12104     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12105     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12106     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12107     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12108     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12109     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
12110     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12111     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12112     { 0 }
12113 };
12114 static const struct message wm_popup_menu_3[] =
12115 {
12116     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12117     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12118     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
12119     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
12120     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
12121     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
12122     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12123     { WM_INITMENU, sent|lparam, 0, 0 },
12124     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12125     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12126     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12127     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12128     { HCBT_CREATEWND, hook },
12129     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12130                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12131     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12132     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12133     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12134     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12135     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12136     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12137     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12138     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12139     { HCBT_DESTROYWND, hook },
12140     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12141     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12142     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12143     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12144     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12145     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
12146     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12147     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12148     { 0 }
12149 };
12150
12151 static const struct message wm_single_menu_item[] =
12152 {
12153     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12154     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12155     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
12156     { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
12157     { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
12158     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
12159     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12160     { WM_INITMENU, sent|lparam, 0, 0 },
12161     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
12162     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12163     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12164     { WM_MENUCOMMAND, sent },
12165     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
12166     { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
12167     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
12168     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
12169
12170     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
12171     { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
12172     { WM_CHAR,  sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
12173     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
12174     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
12175     { 0 }
12176 };
12177
12178 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12179 {
12180     if (message == WM_ENTERIDLE ||
12181         message == WM_INITMENU ||
12182         message == WM_INITMENUPOPUP ||
12183         message == WM_MENUSELECT ||
12184         message == WM_PARENTNOTIFY ||
12185         message == WM_ENTERMENULOOP ||
12186         message == WM_EXITMENULOOP ||
12187         message == WM_UNINITMENUPOPUP ||
12188         message == WM_KEYDOWN ||
12189         message == WM_KEYUP ||
12190         message == WM_CHAR ||
12191         message == WM_SYSKEYDOWN ||
12192         message == WM_SYSKEYUP ||
12193         message == WM_SYSCHAR ||
12194         message == WM_COMMAND ||
12195         message == WM_MENUCOMMAND)
12196     {
12197         struct recvd_message msg;
12198
12199         msg.hwnd = hwnd;
12200         msg.message = message;
12201         msg.flags = sent|wparam|lparam;
12202         msg.wParam = wp;
12203         msg.lParam = lp;
12204         msg.descr = "parent_menu_proc";
12205         add_message(&msg);
12206     }
12207
12208     return DefWindowProcA(hwnd, message, wp, lp);
12209 }
12210
12211 static void set_menu_style(HMENU hmenu, DWORD style)
12212 {
12213     MENUINFO mi;
12214     BOOL ret;
12215
12216     mi.cbSize = sizeof(mi);
12217     mi.fMask = MIM_STYLE;
12218     mi.dwStyle = style;
12219     SetLastError(0xdeadbeef);
12220     ret = pSetMenuInfo(hmenu, &mi);
12221     ok(ret, "SetMenuInfo error %u\n", GetLastError());
12222 }
12223
12224 static DWORD get_menu_style(HMENU hmenu)
12225 {
12226     MENUINFO mi;
12227     BOOL ret;
12228
12229     mi.cbSize = sizeof(mi);
12230     mi.fMask = MIM_STYLE;
12231     mi.dwStyle = 0;
12232     SetLastError(0xdeadbeef);
12233     ret = pGetMenuInfo(hmenu, &mi);
12234     ok(ret, "GetMenuInfo error %u\n", GetLastError());
12235
12236     return mi.dwStyle;
12237 }
12238
12239 static void test_menu_messages(void)
12240 {
12241     MSG msg;
12242     WNDCLASSA cls;
12243     HMENU hmenu, hmenu_popup;
12244     HWND hwnd;
12245     DWORD style;
12246
12247     if (!pGetMenuInfo || !pSetMenuInfo)
12248     {
12249         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
12250         return;
12251     }
12252     cls.style = 0;
12253     cls.lpfnWndProc = parent_menu_proc;
12254     cls.cbClsExtra = 0;
12255     cls.cbWndExtra = 0;
12256     cls.hInstance = GetModuleHandleA(0);
12257     cls.hIcon = 0;
12258     cls.hCursor = LoadCursorA(0, IDC_ARROW);
12259     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12260     cls.lpszMenuName = NULL;
12261     cls.lpszClassName = "TestMenuClass";
12262     UnregisterClass(cls.lpszClassName, cls.hInstance);
12263     if (!RegisterClassA(&cls)) assert(0);
12264
12265     SetLastError(0xdeadbeef);
12266     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12267                            100, 100, 200, 200, 0, 0, 0, NULL);
12268     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12269
12270     SetLastError(0xdeadbeef);
12271     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
12272     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12273
12274     SetMenu(hwnd, hmenu);
12275     SetForegroundWindow( hwnd );
12276
12277     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12278     style = get_menu_style(hmenu);
12279     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12280
12281     hmenu_popup = GetSubMenu(hmenu, 0);
12282     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12283     style = get_menu_style(hmenu_popup);
12284     ok(style == 0, "expected 0, got %u\n", style);
12285
12286     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12287     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12288     style = get_menu_style(hmenu_popup);
12289     ok(style == 0, "expected 0, got %u\n", style);
12290
12291     /* Alt+E, Enter */
12292     trace("testing a popup menu command\n");
12293     flush_sequence();
12294     keybd_event(VK_MENU, 0, 0, 0);
12295     keybd_event('E', 0, 0, 0);
12296     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12297     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12298     keybd_event(VK_RETURN, 0, 0, 0);
12299     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12300     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12301     {
12302         TranslateMessage(&msg);
12303         DispatchMessage(&msg);
12304     }
12305     if (!sequence_cnt)  /* we didn't get any message */
12306     {
12307         skip( "queuing key events not supported\n" );
12308         goto done;
12309     }
12310     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12311     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12312     {
12313         win_skip( "menu tracking through VK_MENU not supported\n" );
12314         goto done;
12315     }
12316     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12317
12318     /* Alt+F, Right, Enter */
12319     trace("testing submenu of a popup menu command\n");
12320     flush_sequence();
12321     keybd_event(VK_MENU, 0, 0, 0);
12322     keybd_event('F', 0, 0, 0);
12323     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12324     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12325     keybd_event(VK_RIGHT, 0, 0, 0);
12326     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12327     keybd_event(VK_RETURN, 0, 0, 0);
12328     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12329     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12330     {
12331         TranslateMessage(&msg);
12332         DispatchMessage(&msg);
12333     }
12334     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12335
12336     trace("testing single menu item command\n");
12337     flush_sequence();
12338     keybd_event(VK_MENU, 0, 0, 0);
12339     keybd_event('Q', 0, 0, 0);
12340     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
12341     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12342     keybd_event(VK_ESCAPE, 0, 0, 0);
12343     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
12344     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12345     {
12346         TranslateMessage(&msg);
12347         DispatchMessage(&msg);
12348     }
12349     ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
12350
12351     set_menu_style(hmenu, 0);
12352     style = get_menu_style(hmenu);
12353     ok(style == 0, "expected 0, got %u\n", style);
12354
12355     hmenu_popup = GetSubMenu(hmenu, 0);
12356     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12357     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12358     style = get_menu_style(hmenu_popup);
12359     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12360
12361     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12362     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12363     style = get_menu_style(hmenu_popup);
12364     ok(style == 0, "expected 0, got %u\n", style);
12365
12366     /* Alt+F, Right, Enter */
12367     trace("testing submenu of a popup menu command\n");
12368     flush_sequence();
12369     keybd_event(VK_MENU, 0, 0, 0);
12370     keybd_event('F', 0, 0, 0);
12371     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12372     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12373     keybd_event(VK_RIGHT, 0, 0, 0);
12374     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12375     keybd_event(VK_RETURN, 0, 0, 0);
12376     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12377     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12378     {
12379         TranslateMessage(&msg);
12380         DispatchMessage(&msg);
12381     }
12382     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12383
12384 done:
12385     DestroyWindow(hwnd);
12386     DestroyMenu(hmenu);
12387 }
12388
12389
12390 static void test_paintingloop(void)
12391 {
12392     HWND hwnd;
12393
12394     paint_loop_done = 0;
12395     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12396                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12397                                 100, 100, 100, 100, 0, 0, 0, NULL );
12398     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12399     ShowWindow(hwnd,SW_NORMAL);
12400     SetFocus(hwnd);
12401
12402     while (!paint_loop_done)
12403     {
12404         MSG msg;
12405         if (PeekMessageA(&msg, 0, 0, 0, 1))
12406         {
12407             TranslateMessage(&msg);
12408             DispatchMessage(&msg);
12409         }
12410     }
12411     DestroyWindow(hwnd);
12412 }
12413
12414 static void test_defwinproc(void)
12415 {
12416     HWND hwnd;
12417     MSG msg;
12418     int gotwmquit = FALSE;
12419     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12420     assert(hwnd);
12421     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12422     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12423         if( msg.message == WM_QUIT) gotwmquit = TRUE;
12424         DispatchMessageA( &msg );
12425     }
12426     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
12427     DestroyWindow( hwnd);
12428 }
12429
12430 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
12431 static void clear_clipboard_(int line, HWND hWnd)
12432 {
12433     BOOL succ;
12434     succ = OpenClipboard(hWnd);
12435     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12436     succ = EmptyClipboard();
12437     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12438     succ = CloseClipboard();
12439     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12440 }
12441
12442 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12443 static void expect_HWND_(int line, HWND expected, HWND got)
12444 {
12445     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12446 }
12447
12448 static WNDPROC pOldViewerProc;
12449
12450 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12451 {
12452     static BOOL recursion_guard;
12453
12454     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12455     {
12456         recursion_guard = TRUE;
12457         clear_clipboard(hWnd);
12458         recursion_guard = FALSE;
12459     }
12460     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12461 }
12462
12463 static void test_clipboard_viewers(void)
12464 {
12465     static struct message wm_change_cb_chain[] =
12466     {
12467         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12468         { 0 }
12469     };
12470     static const struct message wm_clipboard_destroyed[] =
12471     {
12472         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12473         { 0 }
12474     };
12475     static struct message wm_clipboard_changed[] =
12476     {
12477         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12478         { 0 }
12479     };
12480     static struct message wm_clipboard_changed_and_owned[] =
12481     {
12482         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12483         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12484         { 0 }
12485     };
12486
12487     HINSTANCE hInst = GetModuleHandleA(NULL);
12488     HWND hWnd1, hWnd2, hWnd3;
12489     HWND hOrigViewer;
12490     HWND hRet;
12491
12492     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12493         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12494         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12495         GetDesktopWindow(), NULL, hInst, NULL);
12496     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12497         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12498         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12499         GetDesktopWindow(), NULL, hInst, NULL);
12500     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12501         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12502         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12503         GetDesktopWindow(), NULL, hInst, NULL);
12504     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12505     assert(hWnd1 && hWnd2 && hWnd3);
12506
12507     flush_sequence();
12508
12509     /* Test getting the clipboard viewer and setting the viewer to NULL. */
12510     hOrigViewer = GetClipboardViewer();
12511     hRet = SetClipboardViewer(NULL);
12512     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12513     expect_HWND(hOrigViewer, hRet);
12514     expect_HWND(NULL, GetClipboardViewer());
12515
12516     /* Test registering hWnd1 as a viewer. */
12517     hRet = SetClipboardViewer(hWnd1);
12518     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12519     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12520     expect_HWND(NULL, hRet);
12521     expect_HWND(hWnd1, GetClipboardViewer());
12522
12523     /* Test that changing the clipboard actually refreshes the registered viewer. */
12524     clear_clipboard(hWnd1);
12525     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12526     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12527
12528     /* Again, but with different owner. */
12529     clear_clipboard(hWnd2);
12530     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12531     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12532
12533     /* Test re-registering same window. */
12534     hRet = SetClipboardViewer(hWnd1);
12535     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12536     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12537     expect_HWND(hWnd1, hRet);
12538     expect_HWND(hWnd1, GetClipboardViewer());
12539
12540     /* Test ChangeClipboardChain. */
12541     ChangeClipboardChain(hWnd2, hWnd3);
12542     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12543     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12544     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12545     expect_HWND(hWnd1, GetClipboardViewer());
12546
12547     ChangeClipboardChain(hWnd2, NULL);
12548     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12549     wm_change_cb_chain[0].lParam = 0;
12550     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12551     expect_HWND(hWnd1, GetClipboardViewer());
12552
12553     ChangeClipboardChain(NULL, hWnd2);
12554     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12555     expect_HWND(hWnd1, GetClipboardViewer());
12556
12557     /* Actually change clipboard viewer with ChangeClipboardChain. */
12558     ChangeClipboardChain(hWnd1, hWnd2);
12559     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12560     expect_HWND(hWnd2, GetClipboardViewer());
12561
12562     /* Test that no refresh messages are sent when viewer has unregistered. */
12563     clear_clipboard(hWnd2);
12564     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12565
12566     /* Register hWnd1 again. */
12567     ChangeClipboardChain(hWnd2, hWnd1);
12568     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12569     expect_HWND(hWnd1, GetClipboardViewer());
12570
12571     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12572      * changes the clipboard. When this happens, the system shouldn't send
12573      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12574      */
12575     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12576     clear_clipboard(hWnd2);
12577     /* The clipboard owner is changed in recursive_viewer_proc: */
12578     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
12579     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
12580
12581     /* Test unregistering. */
12582     ChangeClipboardChain(hWnd1, NULL);
12583     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
12584     expect_HWND(NULL, GetClipboardViewer());
12585
12586     clear_clipboard(hWnd1);
12587     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
12588
12589     DestroyWindow(hWnd1);
12590     DestroyWindow(hWnd2);
12591     DestroyWindow(hWnd3);
12592     SetClipboardViewer(hOrigViewer);
12593 }
12594
12595 static void test_PostMessage(void)
12596 {
12597     static const struct
12598     {
12599         HWND hwnd;
12600         BOOL ret;
12601     } data[] =
12602     {
12603         { HWND_TOP /* 0 */, TRUE },
12604         { HWND_BROADCAST, TRUE },
12605         { HWND_BOTTOM, TRUE },
12606         { HWND_TOPMOST, TRUE },
12607         { HWND_NOTOPMOST, FALSE },
12608         { HWND_MESSAGE, FALSE },
12609         { (HWND)0xdeadbeef, FALSE }
12610     };
12611     int i;
12612     HWND hwnd;
12613     BOOL ret;
12614     MSG msg;
12615     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
12616
12617     SetLastError(0xdeadbeef);
12618     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12619     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
12620     {
12621         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
12622         return;
12623     }
12624     assert(hwnd);
12625
12626     flush_events();
12627
12628     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
12629     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
12630
12631     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
12632     {
12633         memset(&msg, 0xab, sizeof(msg));
12634         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
12635         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
12636         if (data[i].ret)
12637         {
12638             if (data[i].hwnd)
12639                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
12640                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
12641                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
12642                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
12643             else
12644                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
12645                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
12646                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
12647                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
12648         }
12649     }
12650
12651     DestroyWindow(hwnd);
12652     flush_events();
12653 }
12654
12655 static const struct
12656 {
12657     DWORD exp, broken;
12658     BOOL todo;
12659 } wait_idle_expect[] =
12660 {
12661 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12662          { WAIT_TIMEOUT, 0,            FALSE },
12663          { WAIT_TIMEOUT, 0,            FALSE },
12664          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12665          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12666 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
12667          { WAIT_TIMEOUT, 0,            FALSE },
12668          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12669          { 0,            0,            FALSE },
12670          { 0,            0,            FALSE },
12671 /* 10 */ { 0,            0,            FALSE },
12672          { 0,            0,            FALSE },
12673          { 0,            WAIT_TIMEOUT, FALSE },
12674          { 0,            0,            FALSE },
12675          { 0,            0,            FALSE },
12676 /* 15 */ { 0,            0,            FALSE },
12677          { WAIT_TIMEOUT, 0,            FALSE },
12678          { WAIT_TIMEOUT, 0,            FALSE },
12679          { WAIT_TIMEOUT, 0,            FALSE },
12680          { WAIT_TIMEOUT, 0,            FALSE },
12681 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
12682 };
12683
12684 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
12685 {
12686     MSG msg;
12687
12688     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12689     Sleep( 200 );
12690     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12691     return 0;
12692 }
12693
12694 static void do_wait_idle_child( int arg )
12695 {
12696     WNDCLASS cls;
12697     MSG msg;
12698     HWND hwnd = 0;
12699     HANDLE thread;
12700     DWORD id;
12701     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
12702     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
12703
12704     memset( &cls, 0, sizeof(cls) );
12705     cls.lpfnWndProc   = DefWindowProc;
12706     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12707     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12708     cls.lpszClassName = "TestClass";
12709     RegisterClass( &cls );
12710
12711     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
12712
12713     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
12714     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
12715
12716     switch (arg)
12717     {
12718     case 0:
12719         SetEvent( start_event );
12720         break;
12721     case 1:
12722         SetEvent( start_event );
12723         Sleep( 200 );
12724         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12725         break;
12726     case 2:
12727         SetEvent( start_event );
12728         Sleep( 200 );
12729         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12730         PostThreadMessage( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
12731         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12732         break;
12733     case 3:
12734         SetEvent( start_event );
12735         Sleep( 200 );
12736         SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
12737         break;
12738     case 4:
12739         SetEvent( start_event );
12740         Sleep( 200 );
12741         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12742         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12743         break;
12744     case 5:
12745         SetEvent( start_event );
12746         Sleep( 200 );
12747         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12748         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12749         break;
12750     case 6:
12751         SetEvent( start_event );
12752         Sleep( 200 );
12753         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12754         while (PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ))
12755         {
12756             GetMessage( &msg, 0, 0, 0 );
12757             DispatchMessage( &msg );
12758         }
12759         break;
12760     case 7:
12761         SetEvent( start_event );
12762         Sleep( 200 );
12763         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12764         SetTimer( hwnd, 3, 1, NULL );
12765         Sleep( 200 );
12766         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12767         break;
12768     case 8:
12769         SetEvent( start_event );
12770         Sleep( 200 );
12771         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12772         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12773         break;
12774     case 9:
12775         SetEvent( start_event );
12776         Sleep( 200 );
12777         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12778         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12779         for (;;) GetMessage( &msg, 0, 0, 0 );
12780         break;
12781     case 10:
12782         SetEvent( start_event );
12783         Sleep( 200 );
12784         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12785         SetTimer( hwnd, 3, 1, NULL );
12786         Sleep( 200 );
12787         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12788         break;
12789     case 11:
12790         SetEvent( start_event );
12791         Sleep( 200 );
12792         return;  /* exiting the process makes WaitForInputIdle return success too */
12793     case 12:
12794         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12795         Sleep( 200 );
12796         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12797         SetEvent( start_event );
12798         break;
12799     case 13:
12800         SetEvent( start_event );
12801         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12802         Sleep( 200 );
12803         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
12804         WaitForSingleObject( thread, 10000 );
12805         CloseHandle( thread );
12806         break;
12807     case 14:
12808         SetEvent( start_event );
12809         Sleep( 200 );
12810         PeekMessage( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
12811         break;
12812     case 15:
12813         SetEvent( start_event );
12814         Sleep( 200 );
12815         PeekMessage( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
12816         break;
12817     case 16:
12818         SetEvent( start_event );
12819         Sleep( 200 );
12820         PeekMessage( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
12821         break;
12822     case 17:
12823         SetEvent( start_event );
12824         Sleep( 200 );
12825         PeekMessage( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
12826         break;
12827     case 18:
12828         SetEvent( start_event );
12829         Sleep( 200 );
12830         PeekMessage( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
12831         break;
12832     case 19:
12833         SetEvent( start_event );
12834         Sleep( 200 );
12835         PeekMessage( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
12836         break;
12837     case 20:
12838         SetEvent( start_event );
12839         Sleep( 200 );
12840         PeekMessage( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
12841         break;
12842     }
12843     WaitForSingleObject( end_event, 2000 );
12844     CloseHandle( start_event );
12845     CloseHandle( end_event );
12846     if (hwnd) DestroyWindow( hwnd );
12847 }
12848
12849 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
12850 {
12851     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
12852     return DefWindowProcA( hwnd, msg, wp, lp );
12853 }
12854
12855 static DWORD CALLBACK wait_idle_thread( void *arg )
12856 {
12857     WNDCLASS cls;
12858     MSG msg;
12859     HWND hwnd;
12860
12861     memset( &cls, 0, sizeof(cls) );
12862     cls.lpfnWndProc   = wait_idle_proc;
12863     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12864     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12865     cls.lpszClassName = "TestClass";
12866     RegisterClass( &cls );
12867
12868     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
12869     while (GetMessage( &msg, 0, 0, 0 )) DispatchMessage( &msg );
12870     DestroyWindow(hwnd);
12871     return 0;
12872 }
12873
12874 static void test_WaitForInputIdle( char *argv0 )
12875 {
12876     char path[MAX_PATH];
12877     PROCESS_INFORMATION pi;
12878     STARTUPINFOA startup;
12879     BOOL ret;
12880     HANDLE start_event, end_event, thread;
12881     unsigned int i;
12882     DWORD id;
12883     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
12884     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
12885     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
12886
12887     if (console_app)  /* build the test with -mwindows for better coverage */
12888         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
12889
12890     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
12891     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
12892     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
12893     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
12894
12895     memset( &startup, 0, sizeof(startup) );
12896     startup.cb = sizeof(startup);
12897     startup.dwFlags = STARTF_USESHOWWINDOW;
12898     startup.wShowWindow = SW_SHOWNORMAL;
12899
12900     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
12901
12902     for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
12903     {
12904         ResetEvent( start_event );
12905         ResetEvent( end_event );
12906         sprintf( path, "%s msg %u", argv0, i );
12907         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
12908         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
12909         if (ret)
12910         {
12911             ret = WaitForSingleObject( start_event, 5000 );
12912             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
12913             if (ret == WAIT_OBJECT_0)
12914             {
12915                 ret = WaitForInputIdle( pi.hProcess, 1000 );
12916                 if (ret == WAIT_FAILED)
12917                     ok( console_app ||
12918                         ret == wait_idle_expect[i].exp ||
12919                         broken(ret == wait_idle_expect[i].broken),
12920                         "%u: WaitForInputIdle error %08x expected %08x\n",
12921                         i, ret, wait_idle_expect[i].exp );
12922                 else if (wait_idle_expect[i].todo)
12923                     todo_wine
12924                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12925                         "%u: WaitForInputIdle error %08x expected %08x\n",
12926                         i, ret, wait_idle_expect[i].exp );
12927                 else
12928                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12929                         "%u: WaitForInputIdle error %08x expected %08x\n",
12930                         i, ret, wait_idle_expect[i].exp );
12931                 SetEvent( end_event );
12932                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
12933             }
12934             TerminateProcess( pi.hProcess, 0 );  /* just in case */
12935             winetest_wait_child_process( pi.hProcess );
12936             ret = WaitForInputIdle( pi.hProcess, 100 );
12937             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
12938             CloseHandle( pi.hProcess );
12939             CloseHandle( pi.hThread );
12940         }
12941     }
12942     CloseHandle( start_event );
12943     PostThreadMessage( id, WM_QUIT, 0, 0 );
12944     WaitForSingleObject( thread, 10000 );
12945     CloseHandle( thread );
12946 }
12947
12948 static const struct message WmSetParentSeq_1[] = {
12949     { WM_SHOWWINDOW, sent|wparam, 0 },
12950     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12952     { WM_CHILDACTIVATE, sent },
12953     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
12954     { WM_MOVE, sent|defwinproc|wparam, 0 },
12955     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12956     { WM_SHOWWINDOW, sent|wparam, 1 },
12957     { 0 }
12958 };
12959
12960 static const struct message WmSetParentSeq_2[] = {
12961     { WM_SHOWWINDOW, sent|wparam, 0 },
12962     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12963     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
12964     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12965     { HCBT_SETFOCUS, hook|optional },
12966     { WM_NCACTIVATE, sent|wparam|optional, 0 },
12967     { WM_ACTIVATE, sent|wparam|optional, 0 },
12968     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
12969     { WM_KILLFOCUS, sent|wparam, 0 },
12970     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12971     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12972     { HCBT_ACTIVATE, hook|optional },
12973     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
12974     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12975     { WM_NCACTIVATE, sent|wparam|optional, 1 },
12976     { WM_ACTIVATE, sent|wparam|optional, 1 },
12977     { HCBT_SETFOCUS, hook|optional },
12978     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12979     { WM_SETFOCUS, sent|optional|defwinproc },
12980     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
12981     { WM_MOVE, sent|defwinproc|wparam, 0 },
12982     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12983     { WM_SHOWWINDOW, sent|wparam, 1 },
12984     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12985     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
12986     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12987     { 0 }
12988 };
12989
12990
12991 static void test_SetParent(void)
12992 {
12993     HWND parent1, parent2, child, popup;
12994     RECT rc, rc_old;
12995
12996     parent1 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
12997                             100, 100, 200, 200, 0, 0, 0, NULL);
12998     ok(parent1 != 0, "Failed to create parent1 window\n");
12999
13000     parent2 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13001                             400, 100, 200, 200, 0, 0, 0, NULL);
13002     ok(parent2 != 0, "Failed to create parent2 window\n");
13003
13004     /* WS_CHILD window */
13005     child = CreateWindowEx(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
13006                            10, 10, 150, 150, parent1, 0, 0, NULL);
13007     ok(child != 0, "Failed to create child window\n");
13008
13009     GetWindowRect(parent1, &rc);
13010     trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13011     GetWindowRect(child, &rc_old);
13012     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
13013     trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13014
13015     flush_sequence();
13016
13017     SetParent(child, parent2);
13018     flush_events();
13019     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
13020
13021     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13022     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
13023
13024     GetWindowRect(parent2, &rc);
13025     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13026     GetWindowRect(child, &rc);
13027     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
13028     trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13029
13030     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13031        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13032        rc.left, rc.top, rc.right, rc.bottom );
13033
13034     /* WS_POPUP window */
13035     popup = CreateWindowEx(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
13036                            20, 20, 100, 100, 0, 0, 0, NULL);
13037     ok(popup != 0, "Failed to create popup window\n");
13038
13039     GetWindowRect(popup, &rc_old);
13040     trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
13041
13042     flush_sequence();
13043
13044     SetParent(popup, child);
13045     flush_events();
13046     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
13047
13048     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
13049     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
13050
13051     GetWindowRect(child, &rc);
13052     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13053     GetWindowRect(popup, &rc);
13054     MapWindowPoints(0, child, (POINT *)&rc, 2);
13055     trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
13056
13057     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
13058        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
13059        rc.left, rc.top, rc.right, rc.bottom );
13060
13061     DestroyWindow(popup);
13062     DestroyWindow(child);
13063     DestroyWindow(parent1);
13064     DestroyWindow(parent2);
13065
13066     flush_sequence();
13067 }
13068
13069 static const struct message WmKeyReleaseOnly[] = {
13070     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
13071     { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
13072     { 0 }
13073 };
13074 static const struct message WmKeyPressNormal[] = {
13075     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
13076     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
13077     { 0 }
13078 };
13079 static const struct message WmKeyPressRepeat[] = {
13080     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
13081     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
13082     { 0 }
13083 };
13084 static const struct message WmKeyReleaseNormal[] = {
13085     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
13086     { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
13087     { 0 }
13088 };
13089
13090 static void test_keyflags(void)
13091 {
13092     HWND test_window;
13093     SHORT key_state;
13094     BYTE keyboard_state[256];
13095     MSG msg;
13096
13097     test_window = CreateWindowEx(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13098                            100, 100, 200, 200, 0, 0, 0, NULL);
13099
13100     flush_events();
13101     flush_sequence();
13102
13103     /* keyup without a keydown */
13104     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13105     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13106         DispatchMessage(&msg);
13107     ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
13108
13109     key_state = GetAsyncKeyState(0x41);
13110     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13111
13112     key_state = GetKeyState(0x41);
13113     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13114
13115     /* keydown */
13116     keybd_event(0x41, 0, 0, 0);
13117     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13118         DispatchMessage(&msg);
13119     ok_sequence(WmKeyPressNormal, "key press only", FALSE);
13120
13121     key_state = GetAsyncKeyState(0x41);
13122     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13123
13124     key_state = GetKeyState(0x41);
13125     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13126
13127     /* keydown repeat */
13128     keybd_event(0x41, 0, 0, 0);
13129     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13130         DispatchMessage(&msg);
13131     ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
13132
13133     key_state = GetAsyncKeyState(0x41);
13134     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13135
13136     key_state = GetKeyState(0x41);
13137     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13138
13139     /* keyup */
13140     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13141     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13142         DispatchMessage(&msg);
13143     ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
13144
13145     key_state = GetAsyncKeyState(0x41);
13146     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13147
13148     key_state = GetKeyState(0x41);
13149     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13150
13151     /* set the key state in this thread */
13152     GetKeyboardState(keyboard_state);
13153     keyboard_state[0x41] = 0x80;
13154     SetKeyboardState(keyboard_state);
13155
13156     key_state = GetAsyncKeyState(0x41);
13157     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13158
13159     /* keydown */
13160     keybd_event(0x41, 0, 0, 0);
13161     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13162         DispatchMessage(&msg);
13163     ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
13164
13165     key_state = GetAsyncKeyState(0x41);
13166     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13167
13168     key_state = GetKeyState(0x41);
13169     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13170
13171     /* clear the key state in this thread */
13172     GetKeyboardState(keyboard_state);
13173     keyboard_state[0x41] = 0;
13174     SetKeyboardState(keyboard_state);
13175
13176     key_state = GetAsyncKeyState(0x41);
13177     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13178
13179     /* keyup */
13180     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13181     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13182         DispatchMessage(&msg);
13183     ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
13184
13185     key_state = GetAsyncKeyState(0x41);
13186     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13187
13188     key_state = GetKeyState(0x41);
13189     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13190
13191     DestroyWindow(test_window);
13192     flush_sequence();
13193 }
13194
13195 static const struct message WmHotkeyPressLWIN[] = {
13196     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13197     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13198     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13199     { 0 }
13200 };
13201 static const struct message WmHotkeyPress[] = {
13202     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13203     { WM_HOTKEY, sent|wparam, 5 },
13204     { 0 }
13205 };
13206 static const struct message WmHotkeyRelease[] = {
13207     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13208     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
13209     { WM_KEYUP, sent|lparam, 0, 0x80000001 },
13210     { 0 }
13211 };
13212 static const struct message WmHotkeyReleaseLWIN[] = {
13213     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13214     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13215     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13216     { 0 }
13217 };
13218 static const struct message WmHotkeyCombined[] = {
13219     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13220     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13221     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13222     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13223     { WM_APP, sent, 0, 0 },
13224     { WM_HOTKEY, sent|wparam, 5 },
13225     { WM_APP+1, sent, 0, 0 },
13226     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13227     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13228     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13229     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13230     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13231     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13232     { 0 }
13233 };
13234 static const struct message WmHotkeyPrevious[] = {
13235     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13236     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13237     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13238     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13239     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13240     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13241     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
13242     { WM_KEYDOWN, sent|lparam, 0, 1 },
13243     { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
13244     { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
13245     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13246     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13247     { 0 }
13248 };
13249 static const struct message WmHotkeyNew[] = {
13250     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13251     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13252     { WM_HOTKEY, sent|wparam, 5 },
13253     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13254     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13255     { 0 }
13256 };
13257
13258 static int hotkey_letter;
13259
13260 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
13261 {
13262     struct recvd_message msg;
13263
13264     if (nCode == HC_ACTION)
13265     {
13266         KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
13267
13268         msg.hwnd = 0;
13269         msg.message = wParam;
13270         msg.flags = kbd_hook|wparam|lparam;
13271         msg.wParam = kdbhookstruct->vkCode;
13272         msg.lParam = kdbhookstruct->flags;
13273         msg.descr = "KeyboardHookProc";
13274         add_message(&msg);
13275
13276         if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
13277         {
13278             ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
13279                "unexpected keycode %x\n", kdbhookstruct->vkCode);
13280        }
13281     }
13282
13283     return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
13284 }
13285
13286 static void test_hotkey(void)
13287 {
13288     HWND test_window, taskbar_window;
13289     BOOL ret;
13290     MSG msg;
13291     DWORD queue_status;
13292     SHORT key_state;
13293
13294     SetLastError(0xdeadbeef);
13295     ret = UnregisterHotKey(NULL, 0);
13296     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13297     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13298        "unexpected error %d\n", GetLastError());
13299
13300     if (ret == TRUE)
13301     {
13302         skip("hotkeys not supported\n");
13303         return;
13304     }
13305
13306     test_window = CreateWindowEx(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13307                            100, 100, 200, 200, 0, 0, 0, NULL);
13308
13309     flush_sequence();
13310
13311     SetLastError(0xdeadbeef);
13312     ret = UnregisterHotKey(test_window, 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     /* Search for a Windows Key + letter combination that hasn't been registered */
13318     for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
13319     {
13320         SetLastError(0xdeadbeef);
13321         ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13322
13323         if (ret == TRUE)
13324         {
13325             break;
13326         }
13327         else
13328         {
13329             ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13330                "unexpected error %d\n", GetLastError());
13331         }
13332     }
13333
13334     if (hotkey_letter == 0x52)
13335     {
13336         ok(0, "Couldn't find any free Windows Key + letter combination\n");
13337         goto end;
13338     }
13339
13340     hKBD_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandle(NULL), 0);
13341     if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
13342
13343     /* Same key combination, different id */
13344     SetLastError(0xdeadbeef);
13345     ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
13346     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13347     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13348        "unexpected error %d\n", GetLastError());
13349
13350     /* Same key combination, different window */
13351     SetLastError(0xdeadbeef);
13352     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13353     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13354     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13355        "unexpected error %d\n", GetLastError());
13356
13357     /* Register the same hotkey twice */
13358     SetLastError(0xdeadbeef);
13359     ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13360     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13361     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13362        "unexpected error %d\n", GetLastError());
13363
13364     /* Window on another thread */
13365     taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
13366     if (!taskbar_window)
13367     {
13368         skip("no taskbar?\n");
13369     }
13370     else
13371     {
13372         SetLastError(0xdeadbeef);
13373         ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
13374         ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13375         ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
13376            "unexpected error %d\n", GetLastError());
13377     }
13378
13379     /* Inject the appropriate key sequence */
13380     keybd_event(VK_LWIN, 0, 0, 0);
13381     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13382         DispatchMessage(&msg);
13383     ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
13384
13385     keybd_event(hotkey_letter, 0, 0, 0);
13386     queue_status = GetQueueStatus(QS_HOTKEY);
13387     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13388     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13389     {
13390         if (msg.message == WM_HOTKEY)
13391         {
13392             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13393             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13394         }
13395         DispatchMessage(&msg);
13396     }
13397     ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
13398
13399     queue_status = GetQueueStatus(QS_HOTKEY);
13400     ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
13401
13402     key_state = GetAsyncKeyState(hotkey_letter);
13403     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13404
13405     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13406     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13407         DispatchMessage(&msg);
13408     ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
13409
13410     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13411     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13412         DispatchMessage(&msg);
13413     ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
13414
13415     /* normal posted WM_HOTKEY messages set QS_HOTKEY */
13416     PostMessage(test_window, WM_HOTKEY, 0, 0);
13417     queue_status = GetQueueStatus(QS_HOTKEY);
13418     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13419     queue_status = GetQueueStatus(QS_POSTMESSAGE);
13420     ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
13421     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13422         DispatchMessage(&msg);
13423     flush_sequence();
13424
13425     /* Send and process all messages at once */
13426     PostMessage(test_window, WM_APP, 0, 0);
13427     keybd_event(VK_LWIN, 0, 0, 0);
13428     keybd_event(hotkey_letter, 0, 0, 0);
13429     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13430     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13431
13432     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13433     {
13434         if (msg.message == WM_HOTKEY)
13435         {
13436             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13437             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13438         }
13439         DispatchMessage(&msg);
13440     }
13441     ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
13442
13443     /* Register same hwnd/id with different key combination */
13444     ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
13445     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13446
13447     /* Previous key combination does not work */
13448     keybd_event(VK_LWIN, 0, 0, 0);
13449     keybd_event(hotkey_letter, 0, 0, 0);
13450     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13451     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13452
13453     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13454         DispatchMessage(&msg);
13455     ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
13456
13457     /* New key combination works */
13458     keybd_event(hotkey_letter, 0, 0, 0);
13459     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13460
13461     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13462     {
13463         if (msg.message == WM_HOTKEY)
13464         {
13465             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13466             ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13467         }
13468         DispatchMessage(&msg);
13469     }
13470     ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
13471
13472     /* Unregister hotkey properly */
13473     ret = UnregisterHotKey(test_window, 5);
13474     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13475
13476     /* Unregister hotkey again */
13477     SetLastError(0xdeadbeef);
13478     ret = UnregisterHotKey(test_window, 5);
13479     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13480     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
13481        "unexpected error %d\n", GetLastError());
13482
13483     /* Register thread hotkey */
13484     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13485     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13486
13487     /* Inject the appropriate key sequence */
13488     keybd_event(VK_LWIN, 0, 0, 0);
13489     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13490     {
13491         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13492         DispatchMessage(&msg);
13493     }
13494     ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
13495
13496     keybd_event(hotkey_letter, 0, 0, 0);
13497     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13498     {
13499         if (msg.message == WM_HOTKEY)
13500         {
13501             struct recvd_message message;
13502             ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
13503             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13504             message.message = msg.message;
13505             message.flags = sent|wparam|lparam;
13506             message.wParam = msg.wParam;
13507             message.lParam = msg.lParam;
13508             message.descr = "test_hotkey thread message";
13509             add_message(&message);
13510         }
13511         else
13512             ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13513         DispatchMessage(&msg);
13514     }
13515     ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
13516
13517     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13518     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13519     {
13520         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13521         DispatchMessage(&msg);
13522     }
13523     ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
13524
13525     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13526     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13527     {
13528         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13529         DispatchMessage(&msg);
13530     }
13531     ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
13532
13533     /* Unregister thread hotkey */
13534     ret = UnregisterHotKey(NULL, 5);
13535     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13536
13537     if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
13538     hKBD_hook = NULL;
13539
13540 end:
13541     UnregisterHotKey(NULL, 5);
13542     UnregisterHotKey(test_window, 5);
13543     DestroyWindow(test_window);
13544     flush_sequence();
13545 }
13546
13547
13548 static const struct message WmSetFocus_1[] = {
13549     { HCBT_SETFOCUS, hook }, /* child */
13550     { HCBT_ACTIVATE, hook }, /* parent */
13551     { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
13552     { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
13553     { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
13554     { WM_NCACTIVATE, sent|parent },
13555     { WM_GETTEXT, sent|defwinproc|parent|optional },
13556     { WM_GETTEXT, sent|defwinproc|parent|optional },
13557     { WM_ACTIVATE, sent|wparam|parent, 1 },
13558     { HCBT_SETFOCUS, hook }, /* parent */
13559     { WM_SETFOCUS, sent|defwinproc|parent },
13560     { WM_KILLFOCUS, sent|parent },
13561     { WM_SETFOCUS, sent },
13562     { 0 }
13563 };
13564 static const struct message WmSetFocus_2[] = {
13565     { HCBT_SETFOCUS, hook }, /* parent */
13566     { WM_KILLFOCUS, sent },
13567     { WM_SETFOCUS, sent|parent },
13568     { 0 }
13569 };
13570 static const struct message WmSetFocus_3[] = {
13571     { HCBT_SETFOCUS, hook }, /* child */
13572     { 0 }
13573 };
13574 static const struct message WmSetFocus_4[] = {
13575     { 0 }
13576 };
13577
13578 static void test_SetFocus(void)
13579 {
13580     HWND parent, old_parent, child, old_focus, old_active;
13581     MSG msg;
13582     struct wnd_event wnd_event;
13583     HANDLE hthread;
13584     DWORD ret, tid;
13585
13586     wnd_event.start_event = CreateEvent(NULL, 0, 0, NULL);
13587     ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
13588     hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
13589     ok(hthread != 0, "CreateThread error %d\n", GetLastError());
13590     ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
13591     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
13592     CloseHandle(wnd_event.start_event);
13593
13594     parent = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
13595                             0, 0, 0, 0, 0, 0, 0, NULL);
13596     ok(parent != 0, "failed to create parent window\n");
13597     child = CreateWindowEx(0, "TestWindowClass", NULL, WS_CHILD,
13598                            0, 0, 0, 0, parent, 0, 0, NULL);
13599     ok(child != 0, "failed to create child window\n");
13600
13601     trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
13602
13603     SetFocus(0);
13604     SetActiveWindow(0);
13605
13606     flush_events();
13607     flush_sequence();
13608
13609     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13610     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13611
13612     log_all_parent_messages++;
13613
13614     old_focus = SetFocus(child);
13615     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13616     ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
13617     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13618     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13619     ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
13620
13621     old_focus = SetFocus(parent);
13622     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13623     ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
13624     ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
13625     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13626     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13627
13628     SetLastError(0xdeadbeef);
13629     old_focus = SetFocus((HWND)0xdeadbeef);
13630     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13631        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
13632     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13633     ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
13634     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13635     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13636     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13637
13638     SetLastError(0xdeadbeef);
13639     old_focus = SetFocus(GetDesktopWindow());
13640     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
13641        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
13642     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13643     ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
13644     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13645     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13646     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13647
13648     SetLastError(0xdeadbeef);
13649     old_focus = SetFocus(wnd_event.hwnd);
13650     ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
13651        broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
13652     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13653     ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
13654     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13655     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13656     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13657
13658     SetLastError(0xdeadbeef);
13659     old_active = SetActiveWindow((HWND)0xdeadbeef);
13660     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
13661        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
13662     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13663     ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
13664     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
13665     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13666     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13667
13668     SetLastError(0xdeadbeef);
13669     old_active = SetActiveWindow(GetDesktopWindow());
13670 todo_wine
13671     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13672     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13673     ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
13674     ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
13675     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13676     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13677
13678     SetLastError(0xdeadbeef);
13679     old_active = SetActiveWindow(wnd_event.hwnd);
13680 todo_wine
13681     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13682     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13683     ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
13684     ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
13685     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13686     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13687
13688     SetLastError(0xdeadbeef);
13689     ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
13690     ok(ret, "AttachThreadInput error %d\n", GetLastError());
13691
13692 todo_wine {
13693     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13694     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13695 }
13696     flush_events();
13697     flush_sequence();
13698
13699     old_focus = SetFocus(wnd_event.hwnd);
13700     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13701     ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
13702     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
13703     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
13704
13705     old_focus = SetFocus(parent);
13706     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13707     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13708     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13709     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13710
13711     flush_events();
13712     flush_sequence();
13713
13714     old_active = SetActiveWindow(wnd_event.hwnd);
13715     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13716     ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
13717     ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
13718     ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
13719
13720     SetLastError(0xdeadbeef);
13721     ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
13722     ok(ret, "AttachThreadInput error %d\n", GetLastError());
13723
13724     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13725     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13726
13727     old_parent = SetParent(child, GetDesktopWindow());
13728     ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
13729
13730     ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
13731     ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
13732
13733     old_focus = SetFocus(parent);
13734     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13735     ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
13736     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13737     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13738
13739     flush_events();
13740     flush_sequence();
13741
13742     SetLastError(0xdeadbeef);
13743     old_focus = SetFocus(child);
13744 todo_wine
13745     ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
13746        broken(GetLastError() == 0) /* XP */ ||
13747        broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
13748     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13749     ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
13750     ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
13751     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13752     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13753
13754     SetLastError(0xdeadbeef);
13755     old_active = SetActiveWindow(child);
13756     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
13757     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
13758     ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
13759     ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
13760     ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
13761     ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
13762
13763     log_all_parent_messages--;
13764
13765     DestroyWindow(child);
13766     DestroyWindow(parent);
13767
13768     ret = PostMessage(wnd_event.hwnd, WM_QUIT, 0, 0);
13769     ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
13770     ret = WaitForSingleObject(hthread, INFINITE);
13771     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
13772     CloseHandle(hthread);
13773 }
13774
13775 START_TEST(msg)
13776 {
13777     char **test_argv;
13778     BOOL ret;
13779     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
13780     HMODULE hModuleImm32;
13781     BOOL (WINAPI *pImmDisableIME)(DWORD);
13782
13783     int argc = winetest_get_mainargs( &test_argv );
13784     if (argc >= 3)
13785     {
13786         unsigned int arg;
13787         /* Child process. */
13788         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
13789         do_wait_idle_child( arg );
13790         return;
13791     }
13792
13793     init_procs();
13794
13795     hModuleImm32 = LoadLibrary("imm32.dll");
13796     if (hModuleImm32) {
13797         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
13798         if (pImmDisableIME)
13799             pImmDisableIME(0);
13800     }
13801     pImmDisableIME = NULL;
13802     FreeLibrary(hModuleImm32);
13803
13804     if (!RegisterWindowClasses()) assert(0);
13805
13806     if (pSetWinEventHook)
13807     {
13808         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
13809                                        GetModuleHandleA(0), win_event_proc,
13810                                        0, GetCurrentThreadId(),
13811                                        WINEVENT_INCONTEXT);
13812         if (pIsWinEventHookInstalled && hEvent_hook)
13813         {
13814             UINT event;
13815             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
13816                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
13817         }
13818     }
13819     if (!hEvent_hook) win_skip( "no win event hook support\n" );
13820
13821     cbt_hook_thread_id = GetCurrentThreadId();
13822     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
13823     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
13824
13825     test_winevents();
13826
13827     /* Fix message sequences before removing 4 lines below */
13828 #if 1
13829     if (pUnhookWinEvent && hEvent_hook)
13830     {
13831         ret = pUnhookWinEvent(hEvent_hook);
13832         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
13833         pUnhookWinEvent = 0;
13834     }
13835     hEvent_hook = 0;
13836 #endif
13837
13838     test_SetFocus();
13839     test_SetParent();
13840     test_PostMessage();
13841     test_ShowWindow();
13842     test_PeekMessage();
13843     test_PeekMessage2();
13844     test_WaitForInputIdle( test_argv[0] );
13845     test_scrollwindowex();
13846     test_messages();
13847     test_setwindowpos();
13848     test_showwindow();
13849     invisible_parent_tests();
13850     test_mdi_messages();
13851     test_button_messages();
13852     test_static_messages();
13853     test_listbox_messages();
13854     test_combobox_messages();
13855     test_wmime_keydown_message();
13856     test_paint_messages();
13857     test_interthread_messages();
13858     test_message_conversion();
13859     test_accelerators();
13860     test_timers();
13861     test_timers_no_wnd();
13862     if (hCBT_hook) test_set_hook();
13863     test_DestroyWindow();
13864     test_DispatchMessage();
13865     test_SendMessageTimeout();
13866     test_edit_messages();
13867     test_quit_message();
13868     test_SetActiveWindow();
13869
13870     if (!pTrackMouseEvent)
13871         win_skip("TrackMouseEvent is not available\n");
13872     else
13873         test_TrackMouseEvent();
13874
13875     test_SetWindowRgn();
13876     test_sys_menu();
13877     test_dialog_messages();
13878     test_EndDialog();
13879     test_nullCallback();
13880     test_dbcs_wm_char();
13881     test_menu_messages();
13882     test_paintingloop();
13883     test_defwinproc();
13884     test_clipboard_viewers();
13885     test_keyflags();
13886     test_hotkey();
13887     /* keep it the last test, under Windows it tends to break the tests
13888      * which rely on active/foreground windows being correct.
13889      */
13890     test_SetForegroundWindow();
13891
13892     UnhookWindowsHookEx(hCBT_hook);
13893     if (pUnhookWinEvent && hEvent_hook)
13894     {
13895         ret = pUnhookWinEvent(hEvent_hook);
13896         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
13897         SetLastError(0xdeadbeef);
13898         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
13899         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
13900            GetLastError() == 0xdeadbeef, /* Win9x */
13901            "unexpected error %d\n", GetLastError());
13902     }
13903 }