jscript: Fix typos in comments, add missing ones.
[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 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE        0x0800
41 #define SWP_NOCLIENTMOVE        0x1000
42 #define SWP_STATECHANGED        0x8000
43
44 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
45
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER         0x0118
52 #endif
53
54 #define WND_PARENT_ID           1
55 #define WND_POPUP_ID            2
56 #define WND_CHILD_ID            3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61
62 /* encoded DRAWITEMSTRUCT into an LPARAM */
63 typedef struct
64 {
65     union
66     {
67         struct
68         {
69             UINT type    : 4;  /* ODT_* flags */
70             UINT ctl_id  : 4;  /* Control ID */
71             UINT item_id : 4;  /* Menu item ID */
72             UINT action  : 4;  /* ODA_* flags */
73             UINT state   : 16; /* ODS_* flags */
74         } item;
75         LPARAM lp;
76     } u;
77 } DRAW_ITEM_STRUCT;
78
79 static BOOL test_DestroyWindow_flag;
80 static HWINEVENTHOOK hEvent_hook;
81 static HHOOK hCBT_hook;
82 static DWORD cbt_hook_thread_id;
83
84 static const WCHAR testWindowClassW[] =
85 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
86
87 /*
88 FIXME: add tests for these
89 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
90  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
91  WS_THICKFRAME: thick border
92  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
93  WS_BORDER (default for overlapped windows): single black border
94  none (default for child (and popup?) windows): no border
95 */
96
97 typedef enum {
98     sent=0x1,
99     posted=0x2,
100     parent=0x4,
101     wparam=0x8,
102     lparam=0x10,
103     defwinproc=0x20,
104     beginpaint=0x40,
105     optional=0x80,
106     hook=0x100,
107     winevent_hook=0x200
108 } msg_flags_t;
109
110 struct message {
111     UINT message;          /* the WM_* code */
112     msg_flags_t flags;     /* message props */
113     WPARAM wParam;         /* expected value of wParam */
114     LPARAM lParam;         /* expected value of lParam */
115     WPARAM wp_mask;        /* mask for wParam checks */
116     LPARAM lp_mask;        /* mask for lParam checks */
117 };
118
119 struct recvd_message {
120     UINT message;          /* the WM_* code */
121     msg_flags_t flags;     /* message props */
122     HWND hwnd;             /* window that received the message */
123     WPARAM wParam;         /* expected value of wParam */
124     LPARAM lParam;         /* expected value of lParam */
125     int line;              /* source line where logged */
126     const char *descr;     /* description for trace output */
127     char output[512];      /* trace output */
128 };
129
130 /* Empty message sequence */
131 static const struct message WmEmptySeq[] =
132 {
133     { 0 }
134 };
135 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
136 static const struct message WmCreateOverlappedSeq[] = {
137     { HCBT_CREATEWND, hook },
138     { WM_GETMINMAXINFO, sent },
139     { WM_NCCREATE, sent },
140     { WM_NCCALCSIZE, sent|wparam, 0 },
141     { 0x0093, sent|defwinproc|optional },
142     { 0x0094, sent|defwinproc|optional },
143     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
144     { WM_CREATE, sent },
145     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
146     { 0 }
147 };
148 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
149  * for a not visible overlapped window.
150  */
151 static const struct message WmSWP_ShowOverlappedSeq[] = {
152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
153     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
154     { WM_NCPAINT, sent|wparam|optional, 1 },
155     { WM_GETTEXT, sent|defwinproc|optional },
156     { WM_ERASEBKGND, sent|optional },
157     { HCBT_ACTIVATE, hook },
158     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
159     { WM_NOTIFYFORMAT, sent|optional },
160     { WM_QUERYUISTATE, sent|optional },
161     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
162     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
163     { WM_ACTIVATEAPP, sent|wparam, 1 },
164     { WM_NCACTIVATE, sent|wparam, 1 },
165     { WM_GETTEXT, sent|defwinproc|optional },
166     { WM_ACTIVATE, sent|wparam, 1 },
167     { HCBT_SETFOCUS, hook },
168     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
169     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
170     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
171     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
172     { WM_GETTEXT, sent|optional },
173     { WM_NCPAINT, sent|wparam|optional, 1 },
174     { WM_GETTEXT, sent|defwinproc|optional },
175     { WM_ERASEBKGND, sent|optional },
176     /* Win9x adds SWP_NOZORDER below */
177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
178     { WM_GETTEXT, sent|optional },
179     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
180     { WM_NCPAINT, sent|wparam|optional, 1 },
181     { WM_ERASEBKGND, sent|optional },
182     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
183     { WM_SYNCPAINT, sent|optional },
184     { WM_GETTITLEBARINFOEX, sent|optional },
185     { WM_PAINT, sent|optional },
186     { WM_NCPAINT, sent|beginpaint|optional },
187     { WM_GETTEXT, sent|defwinproc|optional },
188     { WM_ERASEBKGND, sent|beginpaint|optional },
189     { 0 }
190 };
191 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
192  * for a visible overlapped window.
193  */
194 static const struct message WmSWP_HideOverlappedSeq[] = {
195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
196     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
197     { HCBT_ACTIVATE, hook|optional },
198     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
199     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
200     { WM_NCACTIVATE, sent|optional },
201     { WM_ACTIVATE, sent|optional },
202     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
203     { 0 }
204 };
205
206 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
207  * for a visible overlapped window.
208  */
209 static const struct message WmSWP_ResizeSeq[] = {
210     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
211     { WM_GETMINMAXINFO, sent|defwinproc },
212     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
213     { WM_NCPAINT, sent|optional },
214     { WM_GETTEXT, sent|defwinproc|optional },
215     { WM_ERASEBKGND, sent|optional },
216     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
217     { WM_SIZE, sent|defwinproc|optional },
218     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
219     { WM_NCPAINT, sent|optional },
220     { WM_GETTEXT, sent|defwinproc|optional },
221     { WM_ERASEBKGND, sent|optional },
222     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
224     { 0 }
225 };
226
227 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
228  * for a visible popup window.
229  */
230 static const struct message WmSWP_ResizePopupSeq[] = {
231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
232     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
233     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
234     { WM_NCPAINT, sent|optional },
235     { WM_GETTEXT, sent|defwinproc|optional },
236     { WM_ERASEBKGND, sent|optional },
237     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
238     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
239     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
240     { WM_NCPAINT, sent|optional },
241     { WM_GETTEXT, sent|defwinproc|optional },
242     { WM_ERASEBKGND, sent|optional },
243     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
244     { 0 }
245 };
246
247 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
248  * for a visible overlapped window.
249  */
250 static const struct message WmSWP_MoveSeq[] = {
251     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
252     { WM_NCPAINT, sent|optional },
253     { WM_GETTEXT, sent|defwinproc|optional },
254     { WM_ERASEBKGND, sent|optional },
255     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
256     { WM_MOVE, sent|defwinproc|wparam, 0 },
257     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
258     { 0 }
259 };
260 /* Resize with SetWindowPos(SWP_NOZORDER)
261  * for a visible overlapped window
262  * SWP_NOZORDER is stripped by the logging code
263  */
264 static const struct message WmSWP_ResizeNoZOrder[] = {
265     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
266     { WM_GETMINMAXINFO, sent|defwinproc },
267     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
268     { WM_NCPAINT, sent|optional },
269     { WM_GETTEXT, sent|defwinproc|optional },
270     { WM_ERASEBKGND, sent|optional },
271     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
272       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
273     { WM_MOVE, sent|defwinproc|optional },
274     { WM_SIZE, sent|defwinproc|optional },
275     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
276     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
277     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
278     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
279     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
280     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
281     { 0 }
282 };
283
284 /* Switch visible mdi children */
285 static const struct message WmSwitchChild[] = {
286     /* Switch MDI child */
287     { WM_MDIACTIVATE, sent },/* in the MDI client */
288     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
289     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
290     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
291     /* Deactivate 2nd MDI child */
292     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
293     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
294     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
295     /* Preparing for maximize and maximaze the 1st MDI child */
296     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
297     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
298     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
299     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
300     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
301     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
302     /* Lock redraw 2nd MDI child */
303     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
304     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
305     /* Restore 2nd MDI child */
306     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
307     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
308     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
309     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
310     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
311     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
312     /* Redraw 2nd MDI child */
313     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
314     /* Redraw MDI frame */
315     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
316     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
317     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
318     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
320     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
321     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
322     { HCBT_SETFOCUS, hook },
323     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
324     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
325     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
326     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
327     { WM_SETFOCUS, sent },/* in the MDI client */
328     { HCBT_SETFOCUS, hook },
329     { WM_KILLFOCUS, sent },/* in the MDI client */
330     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
331     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
332     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
333     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
334     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
335     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
336     { 0 }
337 };
338
339 /* Switch visible not maximized mdi children */
340 static const struct message WmSwitchNotMaximizedChild[] = {
341     /* Switch not maximized MDI child */
342     { WM_MDIACTIVATE, sent },/* in the MDI client */
343     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
344     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
345     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
346     /* Deactivate 1st MDI child */
347     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
348     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
349     /* Activate 2nd MDI child */
350     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
351     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
352     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
353     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
354     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
355     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
356     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
357     { HCBT_SETFOCUS, hook },
358     { WM_KILLFOCUS, sent }, /* in the  MDI client */
359     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
360     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
361     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
362     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
363     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
364     { 0 }
365 };
366
367
368 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
369                 SWP_NOZORDER|SWP_FRAMECHANGED)
370  * for a visible overlapped window with WS_CLIPCHILDREN style set.
371  */
372 static const struct message WmSWP_FrameChanged_clip[] = {
373     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
374     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
375     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
376     { WM_GETTEXT, sent|parent|defwinproc|optional },
377     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
378     { WM_NCPAINT, sent }, /* wparam != 1 */
379     { WM_ERASEBKGND, sent },
380     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
381     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
382     { WM_PAINT, sent },
383     { 0 }
384 };
385 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
386                 SWP_NOZORDER|SWP_FRAMECHANGED)
387  * for a visible overlapped window.
388  */
389 static const struct message WmSWP_FrameChangedDeferErase[] = {
390     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
391     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
392     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
393     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
394     { WM_PAINT, sent|parent|optional },
395     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
396     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
397     { WM_PAINT, sent },
398     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
399     { WM_ERASEBKGND, sent|beginpaint|optional },
400     { 0 }
401 };
402
403 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
404                 SWP_NOZORDER|SWP_FRAMECHANGED)
405  * for a visible overlapped window without WS_CLIPCHILDREN style set.
406  */
407 static const struct message WmSWP_FrameChanged_noclip[] = {
408     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
409     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
410     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
411     { WM_GETTEXT, sent|parent|defwinproc|optional },
412     { WM_ERASEBKGND, sent|parent|optional },
413     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
414     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
415     { WM_PAINT, sent },
416     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
417     { WM_ERASEBKGND, sent|beginpaint|optional },
418     { 0 }
419 };
420
421 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
422 static const struct message WmShowOverlappedSeq[] = {
423     { WM_SHOWWINDOW, sent|wparam, 1 },
424     { WM_NCPAINT, sent|wparam|optional, 1 },
425     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
426     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
427     { WM_NCPAINT, sent|wparam|optional, 1 },
428     { WM_GETTEXT, sent|defwinproc|optional },
429     { WM_ERASEBKGND, sent|optional },
430     { HCBT_ACTIVATE, hook },
431     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
432     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
433     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
434     { WM_NCPAINT, sent|wparam|optional, 1 },
435     { WM_ACTIVATEAPP, sent|wparam, 1 },
436     { WM_NCACTIVATE, sent|wparam, 1 },
437     { WM_GETTEXT, sent|defwinproc|optional },
438     { WM_ACTIVATE, sent|wparam, 1 },
439     { HCBT_SETFOCUS, hook },
440     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
441     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
442     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
443     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
444     { WM_GETTEXT, sent|optional },
445     { WM_NCPAINT, sent|wparam|optional, 1 },
446     { WM_GETTEXT, sent|defwinproc|optional },
447     { WM_ERASEBKGND, sent|optional },
448     /* Win9x adds SWP_NOZORDER below */
449     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
450     { WM_NCCALCSIZE, sent|optional },
451     { WM_GETTEXT, sent|optional },
452     { WM_NCPAINT, sent|optional },
453     { WM_ERASEBKGND, sent|optional },
454     { WM_SYNCPAINT, sent|optional },
455 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
456        * messages. Does that mean that CreateWindow doesn't set initial
457        * window dimensions for overlapped windows?
458        */
459     { WM_SIZE, sent },
460     { WM_MOVE, sent },
461 #endif
462     { WM_PAINT, sent|optional },
463     { WM_NCPAINT, sent|beginpaint|optional },
464     { 0 }
465 };
466 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
467 static const struct message WmShowMaxOverlappedSeq[] = {
468     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
469     { WM_GETMINMAXINFO, sent },
470     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
471     { WM_GETMINMAXINFO, sent|defwinproc },
472     { WM_NCCALCSIZE, sent|wparam, TRUE },
473     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
474     { HCBT_ACTIVATE, hook },
475     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
476     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
477     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
478     { WM_ACTIVATEAPP, sent|wparam, 1 },
479     { WM_NCACTIVATE, sent|wparam, 1 },
480     { WM_GETTEXT, sent|defwinproc|optional },
481     { WM_ACTIVATE, sent|wparam, 1 },
482     { HCBT_SETFOCUS, hook },
483     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
484     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
485     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
486     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
487     { WM_GETTEXT, sent|optional },
488     { WM_NCPAINT, sent|wparam|optional, 1 },
489     { WM_GETTEXT, sent|defwinproc|optional },
490     { WM_ERASEBKGND, sent|optional },
491     /* Win9x adds SWP_NOZORDER below */
492     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
493     { WM_MOVE, sent|defwinproc },
494     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
495     { WM_GETTEXT, sent|optional },
496     { WM_NCCALCSIZE, sent|optional },
497     { WM_NCPAINT, sent|optional },
498     { WM_ERASEBKGND, sent|optional },
499     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
500     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
501     { WM_SYNCPAINT, sent|optional },
502     { WM_GETTITLEBARINFOEX, sent|optional },
503     { WM_PAINT, sent|optional },
504     { WM_NCPAINT, sent|beginpaint|optional },
505     { WM_ERASEBKGND, sent|beginpaint|optional },
506     { 0 }
507 };
508 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
509 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
510     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
511     { WM_GETTEXT, sent|optional },
512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
513     { WM_GETMINMAXINFO, sent|defwinproc },
514     { WM_NCCALCSIZE, sent|wparam, TRUE },
515     { WM_NCPAINT, sent|optional },
516     { WM_GETTEXT, sent|defwinproc|optional },
517     { WM_ERASEBKGND, sent|optional },
518     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
519     { WM_MOVE, sent|defwinproc|optional },
520     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
521     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
522     { WM_NCPAINT, sent|optional },
523     { WM_ERASEBKGND, sent|optional },
524     { WM_PAINT, sent|optional },
525     { WM_GETTITLEBARINFOEX, sent|optional },
526     { WM_NCPAINT, sent|beginpaint|optional },
527     { WM_ERASEBKGND, sent|beginpaint|optional },
528     { 0 }
529 };
530 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
531 static const struct message WmShowRestoreMinOverlappedSeq[] = {
532     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
533     { WM_QUERYOPEN, sent|optional },
534     { WM_GETTEXT, sent|optional },
535     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
536     { WM_GETMINMAXINFO, sent|defwinproc },
537     { WM_NCCALCSIZE, sent|wparam, TRUE },
538     { HCBT_ACTIVATE, hook },
539     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
540     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
541     { WM_ACTIVATEAPP, sent|wparam, 1 },
542     { WM_NCACTIVATE, sent|wparam, 1 },
543     { WM_GETTEXT, sent|defwinproc|optional },
544     { WM_ACTIVATE, sent|wparam, 1 },
545     { HCBT_SETFOCUS, hook },
546     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
547     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
548     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
549     { WM_GETTEXT, sent|optional },
550     { WM_NCPAINT, sent|wparam|optional, 1 },
551     { WM_GETTEXT, sent|defwinproc|optional },
552     { WM_ERASEBKGND, sent },
553     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
554     { WM_MOVE, sent|defwinproc },
555     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
556     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
557     { WM_NCPAINT, sent|wparam|optional, 1 },
558     { WM_ERASEBKGND, sent|optional },
559     { WM_ACTIVATE, sent|wparam, 1 },
560     { WM_GETTEXT, sent|optional },
561     { WM_PAINT, sent|optional },
562     { WM_GETTITLEBARINFOEX, sent|optional },
563     { WM_NCPAINT, sent|beginpaint|optional },
564     { WM_ERASEBKGND, sent|beginpaint|optional },
565     { 0 }
566 };
567 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
568 static const struct message WmShowMinOverlappedSeq[] = {
569     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
570     { HCBT_SETFOCUS, hook },
571     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
572     { WM_KILLFOCUS, sent },
573     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
574     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
575     { WM_GETTEXT, sent|optional },
576     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
577     { WM_GETMINMAXINFO, sent|defwinproc },
578     { WM_NCCALCSIZE, sent|wparam, TRUE },
579     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
580     { WM_NCPAINT, sent|optional },
581     { WM_GETTEXT, sent|defwinproc|optional },
582     { WM_WINDOWPOSCHANGED, sent },
583     { WM_MOVE, sent|defwinproc },
584     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
585     { WM_NCCALCSIZE, sent|optional },
586     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
587     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
588     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
589     { WM_NCACTIVATE, sent|wparam, 0 },
590     { WM_GETTEXT, sent|defwinproc|optional },
591     { WM_ACTIVATE, sent },
592     { WM_ACTIVATEAPP, sent|wparam, 0 },
593
594     /* Vista sometimes restores the window right away... */
595     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
596     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
597     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
598     { WM_QUERYOPEN, sent|optional },
599     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
600     { WM_GETMINMAXINFO, sent|optional|defwinproc },
601     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
602     { HCBT_ACTIVATE, hook|optional },
603     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
604     { WM_NCACTIVATE, sent|optional },
605     { WM_GETTEXT, sent|optional },
606     { WM_ACTIVATE, sent|optional|wparam, 1 },
607     { HCBT_SETFOCUS, hook|optional },
608     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
609     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
610     { WM_SETFOCUS, sent|optional },
611     { WM_NCPAINT, sent|optional },
612     { WM_GETTEXT, sent|defwinproc|optional },
613     { WM_ERASEBKGND, sent|optional },
614     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
615     { WM_MOVE, sent|defwinproc|optional },
616     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
617     { WM_ACTIVATE, sent|optional|wparam, 1 },
618     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
619     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
620
621     { WM_PAINT, sent|optional },
622     { WM_NCPAINT, sent|beginpaint|optional },
623     { WM_ERASEBKGND, sent|beginpaint|optional },
624     { 0 }
625 };
626 /* ShowWindow(SW_HIDE) for a visible overlapped window */
627 static const struct message WmHideOverlappedSeq[] = {
628     { WM_SHOWWINDOW, sent|wparam, 0 },
629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
630     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
631     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
632     { WM_SIZE, sent|optional }, /* XP doesn't send it */
633     { WM_MOVE, sent|optional }, /* XP doesn't send it */
634     { WM_NCACTIVATE, sent|wparam, 0 },
635     { WM_ACTIVATE, sent|wparam, 0 },
636     { WM_ACTIVATEAPP, sent|wparam, 0 },
637     { WM_KILLFOCUS, sent|wparam, 0 },
638     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
639     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
640     { 0 }
641 };
642 /* DestroyWindow for a visible overlapped window */
643 static const struct message WmDestroyOverlappedSeq[] = {
644     { HCBT_DESTROYWND, hook },
645     { 0x0090, sent|optional },
646     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
647     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
648     { 0x0090, sent|optional },
649     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
650     { WM_NCACTIVATE, sent|optional|wparam, 0 },
651     { WM_ACTIVATE, sent|optional },
652     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
653     { WM_KILLFOCUS, sent|optional|wparam, 0 },
654     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
655     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
656     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
657     { WM_DESTROY, sent },
658     { WM_NCDESTROY, sent },
659     { 0 }
660 };
661 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
662 static const struct message WmCreateMaxPopupSeq[] = {
663     { HCBT_CREATEWND, hook },
664     { WM_NCCREATE, sent },
665     { WM_NCCALCSIZE, sent|wparam, 0 },
666     { WM_CREATE, sent },
667     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
668     { WM_SIZE, sent|wparam, SIZE_RESTORED },
669     { WM_MOVE, sent },
670     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
671     { WM_GETMINMAXINFO, sent },
672     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
673     { WM_NCCALCSIZE, sent|wparam, TRUE },
674     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
675     { WM_MOVE, sent|defwinproc },
676     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
677     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
678     { WM_SHOWWINDOW, sent|wparam, 1 },
679     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
680     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
681     { HCBT_ACTIVATE, hook },
682     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
683     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
684     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
685     { WM_NCPAINT, sent|wparam|optional, 1 },
686     { WM_ERASEBKGND, sent|optional },
687     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
688     { WM_ACTIVATEAPP, sent|wparam, 1 },
689     { WM_NCACTIVATE, sent },
690     { WM_ACTIVATE, sent|wparam, 1 },
691     { HCBT_SETFOCUS, hook },
692     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
693     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
694     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
695     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
696     { WM_GETTEXT, sent|optional },
697     { WM_SYNCPAINT, sent|wparam|optional, 4 },
698     { WM_NCPAINT, sent|wparam|optional, 1 },
699     { WM_ERASEBKGND, sent|optional },
700     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
701     { WM_ERASEBKGND, sent|defwinproc|optional },
702     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
703     { 0 }
704 };
705 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
706 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
707     { HCBT_CREATEWND, hook },
708     { WM_NCCREATE, sent },
709     { WM_NCCALCSIZE, sent|wparam, 0 },
710     { WM_CREATE, sent },
711     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
712     { WM_SIZE, sent|wparam, SIZE_RESTORED },
713     { WM_MOVE, sent },
714     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
715     { WM_GETMINMAXINFO, sent },
716     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
717     { WM_NCCALCSIZE, sent|wparam, TRUE },
718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
719     { WM_MOVE, sent|defwinproc },
720     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
722     { 0 }
723 };
724 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
725 static const struct message WmShowMaxPopupResizedSeq[] = {
726     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
727     { WM_GETMINMAXINFO, sent },
728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
729     { WM_NCCALCSIZE, sent|wparam, TRUE },
730     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
731     { HCBT_ACTIVATE, hook },
732     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
733     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
734     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
735     { WM_NCPAINT, sent|wparam|optional, 1 },
736     { WM_ERASEBKGND, sent|optional },
737     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
738     { WM_ACTIVATEAPP, sent|wparam, 1 },
739     { WM_NCACTIVATE, sent },
740     { WM_ACTIVATE, sent|wparam, 1 },
741     { HCBT_SETFOCUS, hook },
742     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
743     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
744     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
745     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
746     { WM_GETTEXT, sent|optional },
747     { WM_NCPAINT, sent|wparam|optional, 1 },
748     { WM_ERASEBKGND, sent|optional },
749     { WM_WINDOWPOSCHANGED, sent },
750     /* WinNT4.0 sends WM_MOVE */
751     { WM_MOVE, sent|defwinproc|optional },
752     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
753     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
754     { 0 }
755 };
756 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
757 static const struct message WmShowMaxPopupSeq[] = {
758     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
759     { WM_GETMINMAXINFO, sent },
760     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
761     { WM_NCCALCSIZE, sent|wparam, TRUE },
762     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
763     { HCBT_ACTIVATE, hook },
764     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
765     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
766     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
767     { WM_ACTIVATEAPP, sent|wparam, 1 },
768     { WM_NCACTIVATE, sent },
769     { WM_ACTIVATE, sent|wparam, 1 },
770     { HCBT_SETFOCUS, hook },
771     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
772     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
773     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
774     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
775     { WM_GETTEXT, sent|optional },
776     { WM_SYNCPAINT, sent|wparam|optional, 4 },
777     { WM_NCPAINT, sent|wparam|optional, 1 },
778     { WM_ERASEBKGND, sent|optional },
779     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
780     { WM_ERASEBKGND, sent|defwinproc|optional },
781     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
782     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
783     { 0 }
784 };
785 /* CreateWindow(WS_VISIBLE) for popup window */
786 static const struct message WmCreatePopupSeq[] = {
787     { HCBT_CREATEWND, hook },
788     { WM_NCCREATE, sent },
789     { WM_NCCALCSIZE, sent|wparam, 0 },
790     { WM_CREATE, sent },
791     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
792     { WM_SIZE, sent|wparam, SIZE_RESTORED },
793     { WM_MOVE, sent },
794     { WM_SHOWWINDOW, sent|wparam, 1 },
795     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
796     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
797     { HCBT_ACTIVATE, hook },
798     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
799     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
800     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
801     { WM_NCPAINT, sent|wparam|optional, 1 },
802     { WM_ERASEBKGND, sent|optional },
803     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
804     { WM_ACTIVATEAPP, sent|wparam, 1 },
805     { WM_NCACTIVATE, sent },
806     { WM_ACTIVATE, sent|wparam, 1 },
807     { HCBT_SETFOCUS, hook },
808     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
809     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
810     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
811     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
812     { WM_GETTEXT, sent|optional },
813     { WM_SYNCPAINT, sent|wparam|optional, 4 },
814     { WM_NCPAINT, sent|wparam|optional, 1 },
815     { WM_ERASEBKGND, sent|optional },
816     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
817     { 0 }
818 };
819 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
820 static const struct message WmShowVisMaxPopupSeq[] = {
821     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
822     { WM_GETMINMAXINFO, sent },
823     { WM_GETTEXT, sent|optional },
824     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
825     { WM_GETTEXT, sent|optional },
826     { WM_NCCALCSIZE, sent|wparam, TRUE },
827     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
828     { WM_NCPAINT, sent|wparam|optional, 1 },
829     { WM_ERASEBKGND, sent|optional },
830     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
831     { WM_MOVE, sent|defwinproc },
832     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
833     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
834     { 0 }
835 };
836 /* CreateWindow (for a child popup window, not initially visible) */
837 static const struct message WmCreateChildPopupSeq[] = {
838     { HCBT_CREATEWND, hook },
839     { WM_NCCREATE, sent }, 
840     { WM_NCCALCSIZE, sent|wparam, 0 },
841     { WM_CREATE, sent },
842     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
843     { WM_SIZE, sent|wparam, SIZE_RESTORED },
844     { WM_MOVE, sent },
845     { 0 }
846 };
847 /* CreateWindow (for a popup window, not initially visible,
848  * which sets WS_VISIBLE in WM_CREATE handler)
849  */
850 static const struct message WmCreateInvisiblePopupSeq[] = {
851     { HCBT_CREATEWND, hook },
852     { WM_NCCREATE, sent }, 
853     { WM_NCCALCSIZE, sent|wparam, 0 },
854     { WM_CREATE, sent },
855     { WM_STYLECHANGING, sent },
856     { WM_STYLECHANGED, sent },
857     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
858     { WM_SIZE, sent|wparam, SIZE_RESTORED },
859     { WM_MOVE, sent },
860     { 0 }
861 };
862 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
863  * for a popup window with WS_VISIBLE style set
864  */
865 static const struct message WmShowVisiblePopupSeq_2[] = {
866     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
867     { 0 }
868 };
869 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
870  * for a popup window with WS_VISIBLE style set
871  */
872 static const struct message WmShowVisiblePopupSeq_3[] = {
873     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
874     { HCBT_ACTIVATE, hook },
875     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
876     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
877     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
878     { WM_NCACTIVATE, sent },
879     { WM_ACTIVATE, sent|wparam, 1 },
880     { HCBT_SETFOCUS, hook },
881     { WM_KILLFOCUS, sent|parent },
882     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
883     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
884     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
885     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
886     { WM_SETFOCUS, sent|defwinproc },
887     { WM_GETTEXT, sent|optional },
888     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
889     { 0 }
890 };
891 /* CreateWindow (for child window, not initially visible) */
892 static const struct message WmCreateChildSeq[] = {
893     { HCBT_CREATEWND, hook },
894     { WM_NCCREATE, sent }, 
895     /* child is inserted into parent's child list after WM_NCCREATE returns */
896     { WM_NCCALCSIZE, sent|wparam, 0 },
897     { WM_CREATE, sent },
898     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
899     { WM_SIZE, sent|wparam, SIZE_RESTORED },
900     { WM_MOVE, sent },
901     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
902     { 0 }
903 };
904 /* CreateWindow (for maximized child window, not initially visible) */
905 static const struct message WmCreateMaximizedChildSeq[] = {
906     { HCBT_CREATEWND, hook },
907     { WM_NCCREATE, sent }, 
908     { WM_NCCALCSIZE, sent|wparam, 0 },
909     { WM_CREATE, sent },
910     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
911     { WM_SIZE, sent|wparam, SIZE_RESTORED },
912     { WM_MOVE, sent },
913     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
914     { WM_GETMINMAXINFO, sent },
915     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
916     { WM_NCCALCSIZE, sent|wparam, 1 },
917     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
918     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
919     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
920     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
921     { 0 }
922 };
923 /* CreateWindow (for a child window, initially visible) */
924 static const struct message WmCreateVisibleChildSeq[] = {
925     { HCBT_CREATEWND, hook },
926     { WM_NCCREATE, sent }, 
927     /* child is inserted into parent's child list after WM_NCCREATE returns */
928     { WM_NCCALCSIZE, sent|wparam, 0 },
929     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
930     { WM_CREATE, sent },
931     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
932     { WM_SIZE, sent|wparam, SIZE_RESTORED },
933     { WM_MOVE, sent },
934     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
935     { WM_SHOWWINDOW, sent|wparam, 1 },
936     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
937     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
938     { WM_ERASEBKGND, sent|parent|optional },
939     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
940     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
942     { 0 }
943 };
944 /* ShowWindow(SW_SHOW) for a not visible child window */
945 static const struct message WmShowChildSeq[] = {
946     { WM_SHOWWINDOW, sent|wparam, 1 },
947     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
948     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
949     { WM_ERASEBKGND, sent|parent|optional },
950     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
951     { 0 }
952 };
953 /* ShowWindow(SW_HIDE) for a visible child window */
954 static const struct message WmHideChildSeq[] = {
955     { WM_SHOWWINDOW, sent|wparam, 0 },
956     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
957     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
958     { WM_ERASEBKGND, sent|parent|optional },
959     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
960     { 0 }
961 };
962 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
963 static const struct message WmHideChildSeq2[] = {
964     { WM_SHOWWINDOW, sent|wparam, 0 },
965     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
966     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
967     { WM_ERASEBKGND, sent|parent|optional },
968     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
969     { 0 }
970 };
971 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
972  * for a not visible child window
973  */
974 static const struct message WmShowChildSeq_2[] = {
975     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
976     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
977     { WM_CHILDACTIVATE, sent },
978     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
979     { 0 }
980 };
981 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
982  * for a not visible child window
983  */
984 static const struct message WmShowChildSeq_3[] = {
985     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
986     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
987     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
988     { 0 }
989 };
990 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
991  * for a visible child window with a caption
992  */
993 static const struct message WmShowChildSeq_4[] = {
994     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
995     { WM_CHILDACTIVATE, sent },
996     { 0 }
997 };
998 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
999 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1000     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1001     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1002     { WM_NCCALCSIZE, sent|wparam, 1 },
1003     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1004     { WM_CHILDACTIVATE, sent|optional },
1005     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1006     { WM_MOVE, sent|defwinproc },
1007     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1008     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1009     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1010     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1011     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1012     { WM_GETTEXT, sent|optional },
1013     { 0 }
1014 };
1015 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1016 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1017     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1018     { 0 }
1019 };
1020 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1021 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1022     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1023     { WM_GETMINMAXINFO, sent },
1024     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1025     { WM_NCCALCSIZE, sent|wparam, 1 },
1026     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1027     { WM_CHILDACTIVATE, sent },
1028     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1029     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1030     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1031     { 0 }
1032 };
1033 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1034 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1035     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1036     { 0 }
1037 };
1038 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1039 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1040     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1041     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1042     { WM_NCCALCSIZE, sent|wparam, 1 },
1043     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1044     { WM_CHILDACTIVATE, sent },
1045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1046     { WM_MOVE, sent|defwinproc },
1047     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1048     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1049     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1050     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1051     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1052     { WM_GETTEXT, sent|optional },
1053     { 0 }
1054 };
1055 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1056 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1057     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1058     { 0 }
1059 };
1060 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1061 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1062     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1063     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1064     { WM_NCCALCSIZE, sent|wparam, 1 },
1065     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1066     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1067     { WM_MOVE, sent|defwinproc },
1068     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1069     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1070     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1071     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1072     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1073     { WM_GETTEXT, sent|optional },
1074     { 0 }
1075 };
1076 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1077 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1078     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1079     { 0 }
1080 };
1081 /* ShowWindow(SW_SHOW) for child with invisible parent */
1082 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1083     { WM_SHOWWINDOW, sent|wparam, 1 },
1084     { 0 }
1085 };
1086 /* ShowWindow(SW_HIDE) for child with invisible parent */
1087 static const struct message WmHideChildInvisibleParentSeq[] = {
1088     { WM_SHOWWINDOW, sent|wparam, 0 },
1089     { 0 }
1090 };
1091 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1092 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1093     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1094     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1095     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1096     { 0 }
1097 };
1098 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1099 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1100     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1101     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1102     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1103     { 0 }
1104 };
1105 /* DestroyWindow for a visible child window */
1106 static const struct message WmDestroyChildSeq[] = {
1107     { HCBT_DESTROYWND, hook },
1108     { 0x0090, sent|optional },
1109     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1110     { WM_SHOWWINDOW, sent|wparam, 0 },
1111     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1112     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1113     { WM_ERASEBKGND, sent|parent|optional },
1114     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1115     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1116     { WM_KILLFOCUS, sent },
1117     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1118     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1119     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1120     { WM_SETFOCUS, sent|parent },
1121     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1122     { WM_DESTROY, sent },
1123     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1124     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1125     { WM_NCDESTROY, sent },
1126     { 0 }
1127 };
1128 /* visible child window destroyed by thread exit */
1129 static const struct message WmExitThreadSeq[] = {
1130     { WM_NCDESTROY, sent },  /* actually in grandchild */
1131     { WM_PAINT, sent|parent },
1132     { WM_ERASEBKGND, sent|parent|beginpaint },
1133     { 0 }
1134 };
1135 /* DestroyWindow for a visible child window with invisible parent */
1136 static const struct message WmDestroyInvisibleChildSeq[] = {
1137     { HCBT_DESTROYWND, hook },
1138     { 0x0090, sent|optional },
1139     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1140     { WM_SHOWWINDOW, sent|wparam, 0 },
1141     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1142     { WM_DESTROY, sent },
1143     { WM_NCDESTROY, sent },
1144     { 0 }
1145 };
1146 /* Moving the mouse in nonclient area */
1147 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1148     { WM_NCHITTEST, sent },
1149     { WM_SETCURSOR, sent },
1150     { WM_NCMOUSEMOVE, posted },
1151     { 0 }
1152 };
1153 /* Moving the mouse in client area */
1154 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1155     { WM_NCHITTEST, sent },
1156     { WM_SETCURSOR, sent },
1157     { WM_MOUSEMOVE, posted },
1158     { 0 }
1159 };
1160 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1161 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1162     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1163     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1164     { WM_GETMINMAXINFO, sent|defwinproc },
1165     { WM_ENTERSIZEMOVE, sent|defwinproc },
1166     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1167     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1168     { WM_MOVE, sent|defwinproc },
1169     { WM_EXITSIZEMOVE, sent|defwinproc },
1170     { 0 }
1171 };
1172 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1173 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1174     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1175     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1176     { WM_GETMINMAXINFO, sent|defwinproc },
1177     { WM_ENTERSIZEMOVE, sent|defwinproc },
1178     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1179     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1180     { WM_GETMINMAXINFO, sent|defwinproc },
1181     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1182     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1183     { WM_GETTEXT, sent|defwinproc },
1184     { WM_ERASEBKGND, sent|defwinproc },
1185     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1186     { WM_MOVE, sent|defwinproc },
1187     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1188     { WM_EXITSIZEMOVE, sent|defwinproc },
1189     { 0 }
1190 };
1191 /* Resizing child window with MoveWindow (32) */
1192 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1193     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1194     { WM_NCCALCSIZE, sent|wparam, 1 },
1195     { WM_ERASEBKGND, sent|parent|optional },
1196     { WM_ERASEBKGND, sent|optional },
1197     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1198     { WM_MOVE, sent|defwinproc },
1199     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1200     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1201     { 0 }
1202 };
1203 /* Clicking on inactive button */
1204 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1205     { WM_NCHITTEST, sent },
1206     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1207     { WM_MOUSEACTIVATE, sent },
1208     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1209     { WM_SETCURSOR, sent },
1210     { WM_SETCURSOR, sent|parent|defwinproc },
1211     { WM_LBUTTONDOWN, posted },
1212     { WM_KILLFOCUS, posted|parent },
1213     { WM_SETFOCUS, posted },
1214     { WM_CTLCOLORBTN, posted|parent },
1215     { BM_SETSTATE, posted },
1216     { WM_CTLCOLORBTN, posted|parent },
1217     { WM_LBUTTONUP, posted },
1218     { BM_SETSTATE, posted },
1219     { WM_CTLCOLORBTN, posted|parent },
1220     { WM_COMMAND, posted|parent },
1221     { 0 }
1222 };
1223 /* Reparenting a button (16/32) */
1224 /* The last child (button) reparented gets topmost for its new parent. */
1225 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1226     { WM_SHOWWINDOW, sent|wparam, 0 },
1227     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1228     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1229     { WM_ERASEBKGND, sent|parent },
1230     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1232     { WM_CHILDACTIVATE, sent },
1233     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1234     { WM_MOVE, sent|defwinproc },
1235     { WM_SHOWWINDOW, sent|wparam, 1 },
1236     { 0 }
1237 };
1238 /* Creation of a custom dialog (32) */
1239 static const struct message WmCreateCustomDialogSeq[] = {
1240     { HCBT_CREATEWND, hook },
1241     { WM_GETMINMAXINFO, sent },
1242     { WM_NCCREATE, sent },
1243     { WM_NCCALCSIZE, sent|wparam, 0 },
1244     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1245     { WM_CREATE, sent },
1246     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1247     { WM_NOTIFYFORMAT, sent|optional },
1248     { WM_QUERYUISTATE, sent|optional },
1249     { WM_WINDOWPOSCHANGING, sent|optional },
1250     { WM_GETMINMAXINFO, sent|optional },
1251     { WM_NCCALCSIZE, sent|optional },
1252     { WM_WINDOWPOSCHANGED, sent|optional },
1253     { WM_SHOWWINDOW, sent|wparam, 1 },
1254     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1255     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1256     { HCBT_ACTIVATE, hook },
1257     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1258
1259
1260     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1261
1262     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1263
1264     { WM_NCACTIVATE, sent },
1265     { WM_GETTEXT, sent|optional|defwinproc },
1266     { WM_GETTEXT, sent|optional|defwinproc },
1267     { WM_GETTEXT, sent|optional|defwinproc },
1268     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1269     { WM_ACTIVATE, sent|wparam, 1 },
1270     { WM_GETTEXT, sent|optional },
1271     { WM_KILLFOCUS, sent|parent },
1272     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1273     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1274     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1275     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1276     { WM_SETFOCUS, sent },
1277     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1278     { WM_NCPAINT, sent|wparam, 1 },
1279     { WM_GETTEXT, sent|optional|defwinproc },
1280     { WM_GETTEXT, sent|optional|defwinproc },
1281     { WM_ERASEBKGND, sent },
1282     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1283     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1284     { WM_GETTEXT, sent|optional },
1285     { WM_GETTEXT, sent|optional },
1286     { WM_NCCALCSIZE, sent|optional },
1287     { WM_NCPAINT, sent|optional },
1288     { WM_GETTEXT, sent|optional|defwinproc },
1289     { WM_GETTEXT, sent|optional|defwinproc },
1290     { WM_ERASEBKGND, sent|optional },
1291     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1292     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1293     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1294     { WM_MOVE, sent },
1295     { 0 }
1296 };
1297 /* Calling EndDialog for a custom dialog (32) */
1298 static const struct message WmEndCustomDialogSeq[] = {
1299     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1300     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1301     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1302     { WM_GETTEXT, sent|optional },
1303     { HCBT_ACTIVATE, hook },
1304     { WM_NCACTIVATE, sent|wparam, 0 },
1305     { WM_GETTEXT, sent|optional|defwinproc },
1306     { WM_GETTEXT, sent|optional|defwinproc },
1307     { WM_ACTIVATE, sent|wparam, 0 },
1308     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1309     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1310     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1311     { WM_GETTEXT, sent|optional|defwinproc },
1312     { WM_GETTEXT, sent|optional|defwinproc },
1313     { HCBT_SETFOCUS, hook },
1314     { WM_KILLFOCUS, sent },
1315     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1316     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1317     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1318     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1319     { WM_SETFOCUS, sent|parent|defwinproc },
1320     { 0 }
1321 };
1322 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1323 static const struct message WmShowCustomDialogSeq[] = {
1324     { WM_SHOWWINDOW, sent|wparam, 1 },
1325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1326     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1327     { HCBT_ACTIVATE, hook },
1328     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1329
1330     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1331
1332     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1333     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1334     { WM_NCACTIVATE, sent },
1335     { WM_ACTIVATE, sent|wparam, 1 },
1336     { WM_GETTEXT, sent|optional },
1337
1338     { WM_KILLFOCUS, sent|parent },
1339     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1340     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1341     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1342     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1343     { WM_SETFOCUS, sent },
1344     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1345     { WM_NCPAINT, sent|wparam, 1 },
1346     { WM_ERASEBKGND, sent },
1347     { WM_CTLCOLORDLG, sent|defwinproc },
1348     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1349     { 0 }
1350 };
1351 /* Creation and destruction of a modal dialog (32) */
1352 static const struct message WmModalDialogSeq[] = {
1353     { WM_CANCELMODE, sent|parent },
1354     { HCBT_SETFOCUS, hook },
1355     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1356     { WM_KILLFOCUS, sent|parent },
1357     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1358     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1359     { WM_ENABLE, sent|parent|wparam, 0 },
1360     { HCBT_CREATEWND, hook },
1361     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1362     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1363     { WM_SETFONT, sent },
1364     { WM_INITDIALOG, sent },
1365     { WM_CHANGEUISTATE, sent|optional },
1366     { WM_UPDATEUISTATE, sent|optional },
1367     { WM_SHOWWINDOW, sent },
1368     { HCBT_ACTIVATE, hook },
1369     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1370     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1371     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1372     { WM_NCACTIVATE, sent },
1373     { WM_GETTEXT, sent|optional },
1374     { WM_ACTIVATE, sent|wparam, 1 },
1375     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1376     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1377     { WM_NCPAINT, sent|optional },
1378     { WM_GETTEXT, sent|optional },
1379     { WM_ERASEBKGND, sent|optional },
1380     { WM_CTLCOLORDLG, sent|optional },
1381     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1382     { WM_GETTEXT, sent|optional },
1383     { WM_NCCALCSIZE, sent|optional },
1384     { WM_NCPAINT, sent|optional },
1385     { WM_GETTEXT, sent|optional },
1386     { WM_ERASEBKGND, sent|optional },
1387     { WM_CTLCOLORDLG, sent|optional },
1388     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1389     { WM_PAINT, sent|optional },
1390     { WM_CTLCOLORBTN, sent|optional },
1391     { WM_GETTITLEBARINFOEX, sent|optional },
1392     { WM_ENTERIDLE, sent|parent|optional },
1393     { WM_ENTERIDLE, sent|parent|optional },
1394     { WM_ENTERIDLE, sent|parent|optional },
1395     { WM_ENTERIDLE, sent|parent|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_TIMER, sent },
1413     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1414     { WM_ENABLE, sent|parent|wparam, 1 },
1415     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1416     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1417     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1418     { WM_GETTEXT, sent|optional },
1419     { HCBT_ACTIVATE, hook },
1420     { WM_NCACTIVATE, sent|wparam, 0 },
1421     { WM_GETTEXT, sent|optional },
1422     { WM_ACTIVATE, sent|wparam, 0 },
1423     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1424     { WM_WINDOWPOSCHANGING, sent|optional },
1425     { WM_WINDOWPOSCHANGED, sent|optional },
1426     { HCBT_SETFOCUS, hook },
1427     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1428     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1429     { WM_SETFOCUS, sent|parent|defwinproc },
1430     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1431     { HCBT_DESTROYWND, hook },
1432     { 0x0090, sent|optional },
1433     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1434     { WM_DESTROY, sent },
1435     { WM_NCDESTROY, sent },
1436     { 0 }
1437 };
1438 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1439 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1440     /* (inside dialog proc, handling WM_INITDIALOG) */
1441     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1442     { WM_NCCALCSIZE, sent },
1443     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1444     { WM_GETTEXT, sent|defwinproc },
1445     { WM_ACTIVATE, sent|parent|wparam, 0 },
1446     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1447     { WM_WINDOWPOSCHANGING, sent|parent },
1448     { WM_NCACTIVATE, sent|wparam, 1 },
1449     { WM_ACTIVATE, sent|wparam, 1 },
1450     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1451     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1452     /* (setting focus) */
1453     { WM_SHOWWINDOW, sent|wparam, 1 },
1454     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1455     { WM_NCPAINT, sent },
1456     { WM_GETTEXT, sent|defwinproc },
1457     { WM_ERASEBKGND, sent },
1458     { WM_CTLCOLORDLG, sent|defwinproc },
1459     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1460     { WM_PAINT, sent },
1461     /* (bunch of WM_CTLCOLOR* for each control) */
1462     { WM_PAINT, sent|parent },
1463     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1464     { WM_SETCURSOR, sent|parent },
1465     { 0 }
1466 };
1467 /* SetMenu for NonVisible windows with size change*/
1468 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1469     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1470     { WM_NCCALCSIZE, sent|wparam, 1 },
1471     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1472     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1473     { WM_MOVE, sent|defwinproc },
1474     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1475     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1476     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1477     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1478     { WM_GETTEXT, sent|optional },
1479     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1480     { 0 }
1481 };
1482 /* SetMenu for NonVisible windows with no size change */
1483 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1484     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1485     { WM_NCCALCSIZE, sent|wparam, 1 },
1486     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1487     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1488     { 0 }
1489 };
1490 /* SetMenu for Visible windows with size change */
1491 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1492     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1493     { WM_NCCALCSIZE, sent|wparam, 1 },
1494     { 0x0093, sent|defwinproc|optional },
1495     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1496     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1497     { 0x0093, sent|defwinproc|optional },
1498     { 0x0093, sent|defwinproc|optional },
1499     { 0x0091, sent|defwinproc|optional },
1500     { 0x0092, sent|defwinproc|optional },
1501     { WM_GETTEXT, sent|defwinproc|optional },
1502     { WM_ERASEBKGND, sent|optional },
1503     { WM_ACTIVATE, sent|optional },
1504     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1505     { WM_MOVE, sent|defwinproc },
1506     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1507     { 0x0093, sent|optional },
1508     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1509     { 0x0093, sent|defwinproc|optional },
1510     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1511     { 0x0093, sent|defwinproc|optional },
1512     { 0x0093, sent|defwinproc|optional },
1513     { 0x0091, sent|defwinproc|optional },
1514     { 0x0092, sent|defwinproc|optional },
1515     { WM_ERASEBKGND, sent|optional },
1516     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1517     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1518     { 0 }
1519 };
1520 /* SetMenu for Visible windows with no size change */
1521 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1522     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1523     { WM_NCCALCSIZE, sent|wparam, 1 },
1524     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1525     { WM_GETTEXT, sent|defwinproc|optional },
1526     { WM_ERASEBKGND, sent|optional },
1527     { WM_ACTIVATE, sent|optional },
1528     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1529     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1530     { 0 }
1531 };
1532 /* DrawMenuBar for a visible window */
1533 static const struct message WmDrawMenuBarSeq[] =
1534 {
1535     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1536     { WM_NCCALCSIZE, sent|wparam, 1 },
1537     { 0x0093, sent|defwinproc|optional },
1538     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1539     { 0x0093, sent|defwinproc|optional },
1540     { 0x0093, sent|defwinproc|optional },
1541     { 0x0091, sent|defwinproc|optional },
1542     { 0x0092, sent|defwinproc|optional },
1543     { WM_GETTEXT, sent|defwinproc|optional },
1544     { WM_ERASEBKGND, sent|optional },
1545     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1546     { 0x0093, sent|optional },
1547     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1548     { 0 }
1549 };
1550
1551 static const struct message WmSetRedrawFalseSeq[] =
1552 {
1553     { WM_SETREDRAW, sent|wparam, 0 },
1554     { 0 }
1555 };
1556
1557 static const struct message WmSetRedrawTrueSeq[] =
1558 {
1559     { WM_SETREDRAW, sent|wparam, 1 },
1560     { 0 }
1561 };
1562
1563 static const struct message WmEnableWindowSeq_1[] =
1564 {
1565     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1566     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1567     { HCBT_SETFOCUS, hook|optional },
1568     { WM_KILLFOCUS, sent|optional },
1569     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1570     { 0 }
1571 };
1572
1573 static const struct message WmEnableWindowSeq_2[] =
1574 {
1575     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1576     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1577     { 0 }
1578 };
1579
1580 static const struct message WmGetScrollRangeSeq[] =
1581 {
1582     { SBM_GETRANGE, sent },
1583     { 0 }
1584 };
1585 static const struct message WmGetScrollInfoSeq[] =
1586 {
1587     { SBM_GETSCROLLINFO, sent },
1588     { 0 }
1589 };
1590 static const struct message WmSetScrollRangeSeq[] =
1591 {
1592     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1593        sends SBM_SETSCROLLINFO.
1594      */
1595     { SBM_SETSCROLLINFO, sent },
1596     { 0 }
1597 };
1598 /* SetScrollRange for a window without a non-client area */
1599 static const struct message WmSetScrollRangeHSeq_empty[] =
1600 {
1601     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1602     { 0 }
1603 };
1604 static const struct message WmSetScrollRangeVSeq_empty[] =
1605 {
1606     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1607     { 0 }
1608 };
1609 static const struct message WmSetScrollRangeHVSeq[] =
1610 {
1611     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1612     { WM_NCCALCSIZE, sent|wparam, 1 },
1613     { WM_GETTEXT, sent|defwinproc|optional },
1614     { WM_ERASEBKGND, sent|optional },
1615     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1616     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1617     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1618     { 0 }
1619 };
1620 /* SetScrollRange for a window with a non-client area */
1621 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1622 {
1623     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1624     { WM_NCCALCSIZE, sent|wparam, 1 },
1625     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1626     { WM_NCPAINT, sent|optional },
1627     { WM_STYLECHANGING, sent|defwinproc|optional },
1628     { WM_STYLECHANGED, sent|defwinproc|optional },
1629     { WM_STYLECHANGING, sent|defwinproc|optional },
1630     { WM_STYLECHANGED, sent|defwinproc|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_GETTEXT, sent|defwinproc|optional },
1636     { WM_GETTEXT, sent|defwinproc|optional },
1637     { WM_ERASEBKGND, sent|optional },
1638     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1639     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1640     { WM_SIZE, sent|defwinproc|optional },
1641     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1642     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1643     { WM_GETTEXT, sent|optional },
1644     { WM_GETTEXT, sent|optional },
1645     { WM_GETTEXT, sent|optional },
1646     { WM_GETTEXT, sent|optional },
1647     { 0 }
1648 };
1649 /* test if we receive the right sequence of messages */
1650 /* after calling ShowWindow( SW_SHOWNA) */
1651 static const struct message WmSHOWNAChildInvisParInvis[] = {
1652     { WM_SHOWWINDOW, sent|wparam, 1 },
1653     { 0 }
1654 };
1655 static const struct message WmSHOWNAChildVisParInvis[] = {
1656     { WM_SHOWWINDOW, sent|wparam, 1 },
1657     { 0 }
1658 };
1659 static const struct message WmSHOWNAChildVisParVis[] = {
1660     { WM_SHOWWINDOW, sent|wparam, 1 },
1661     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1662     { 0 }
1663 };
1664 static const struct message WmSHOWNAChildInvisParVis[] = {
1665     { WM_SHOWWINDOW, sent|wparam, 1 },
1666     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1667     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1668     { WM_ERASEBKGND, sent|optional },
1669     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1670     { 0 }
1671 };
1672 static const struct message WmSHOWNATopVisible[] = {
1673     { WM_SHOWWINDOW, sent|wparam, 1 },
1674     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1675     { WM_NCPAINT, sent|wparam|optional, 1 },
1676     { WM_GETTEXT, sent|defwinproc|optional },
1677     { WM_ERASEBKGND, sent|optional },
1678     { WM_WINDOWPOSCHANGED, sent|optional },
1679     { 0 }
1680 };
1681 static const struct message WmSHOWNATopInvisible[] = {
1682     { WM_NOTIFYFORMAT, sent|optional },
1683     { WM_QUERYUISTATE, sent|optional },
1684     { WM_WINDOWPOSCHANGING, sent|optional },
1685     { WM_GETMINMAXINFO, sent|optional },
1686     { WM_NCCALCSIZE, sent|optional },
1687     { WM_WINDOWPOSCHANGED, sent|optional },
1688     { WM_SHOWWINDOW, sent|wparam, 1 },
1689     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1690     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1691     { WM_NCPAINT, sent|wparam|optional, 1 },
1692     { WM_GETTEXT, sent|defwinproc|optional },
1693     { WM_ERASEBKGND, sent|optional },
1694     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1695     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1696     { WM_NCPAINT, sent|wparam|optional, 1 },
1697     { WM_ERASEBKGND, sent|optional },
1698     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1699     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1700     { WM_MOVE, sent },
1701     { 0 }
1702 };
1703
1704 static int after_end_dialog, test_def_id;
1705 static int sequence_cnt, sequence_size;
1706 static struct recvd_message* sequence;
1707 static int log_all_parent_messages;
1708 static int paint_loop_done;
1709
1710 /* user32 functions */
1711 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1712 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1713 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1714 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1715 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1716 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1717 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1718 /* kernel32 functions */
1719 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1720
1721 static void init_procs(void)
1722 {
1723     HMODULE user32 = GetModuleHandleA("user32.dll");
1724     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1725
1726 #define GET_PROC(dll, func) \
1727     p ## func = (void*)GetProcAddress(dll, #func); \
1728     if(!p ## func) { \
1729       trace("GetProcAddress(%s) failed\n", #func); \
1730     }
1731
1732     GET_PROC(user32, GetAncestor)
1733     GET_PROC(user32, GetMenuInfo)
1734     GET_PROC(user32, NotifyWinEvent)
1735     GET_PROC(user32, SetMenuInfo)
1736     GET_PROC(user32, SetWinEventHook)
1737     GET_PROC(user32, TrackMouseEvent)
1738     GET_PROC(user32, UnhookWinEvent)
1739
1740     GET_PROC(kernel32, GetCPInfoExA)
1741
1742 #undef GET_PROC
1743 }
1744
1745 static const char *get_winpos_flags(UINT flags)
1746 {
1747     static char buffer[300];
1748
1749     buffer[0] = 0;
1750 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1751     DUMP( SWP_SHOWWINDOW );
1752     DUMP( SWP_HIDEWINDOW );
1753     DUMP( SWP_NOACTIVATE );
1754     DUMP( SWP_FRAMECHANGED );
1755     DUMP( SWP_NOCOPYBITS );
1756     DUMP( SWP_NOOWNERZORDER );
1757     DUMP( SWP_NOSENDCHANGING );
1758     DUMP( SWP_DEFERERASE );
1759     DUMP( SWP_ASYNCWINDOWPOS );
1760     DUMP( SWP_NOZORDER );
1761     DUMP( SWP_NOREDRAW );
1762     DUMP( SWP_NOSIZE );
1763     DUMP( SWP_NOMOVE );
1764     DUMP( SWP_NOCLIENTSIZE );
1765     DUMP( SWP_NOCLIENTMOVE );
1766     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1767     return buffer + 1;
1768 #undef DUMP
1769 }
1770
1771 static BOOL ignore_message( UINT message )
1772 {
1773     /* these are always ignored */
1774     return (message >= 0xc000 ||
1775             message == WM_GETICON ||
1776             message == WM_GETOBJECT ||
1777             message == WM_TIMECHANGE ||
1778             message == WM_DISPLAYCHANGE ||
1779             message == WM_DEVICECHANGE);
1780 }
1781
1782
1783 #define add_message(msg) add_message_(__LINE__,msg);
1784 static void add_message_(int line, const struct recvd_message *msg)
1785 {
1786     struct recvd_message *seq;
1787
1788     if (!sequence) 
1789     {
1790         sequence_size = 10;
1791         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1792     }
1793     if (sequence_cnt == sequence_size) 
1794     {
1795         sequence_size *= 2;
1796         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1797     }
1798     assert(sequence);
1799
1800     seq = &sequence[sequence_cnt];
1801     seq->hwnd = msg->hwnd;
1802     seq->message = msg->message;
1803     seq->flags = msg->flags;
1804     seq->wParam = msg->wParam;
1805     seq->lParam = msg->lParam;
1806     seq->line   = line;
1807     seq->descr  = msg->descr;
1808     seq->output[0] = 0;
1809
1810     if (msg->descr)
1811     {
1812         if (msg->flags & hook)
1813         {
1814             static const char * const CBT_code_name[10] =
1815             {
1816                 "HCBT_MOVESIZE",
1817                 "HCBT_MINMAX",
1818                 "HCBT_QS",
1819                 "HCBT_CREATEWND",
1820                 "HCBT_DESTROYWND",
1821                 "HCBT_ACTIVATE",
1822                 "HCBT_CLICKSKIPPED",
1823                 "HCBT_KEYSKIPPED",
1824                 "HCBT_SYSCOMMAND",
1825                 "HCBT_SETFOCUS"
1826             };
1827             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1828
1829             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1830                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1831         }
1832         else if (msg->flags & winevent_hook)
1833         {
1834             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1835                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1836         }
1837         else
1838         {
1839             switch (msg->message)
1840             {
1841             case WM_WINDOWPOSCHANGING:
1842             case WM_WINDOWPOSCHANGED:
1843             {
1844                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1845
1846                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1847                           msg->descr, msg->hwnd,
1848                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1849                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1850                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1851                           get_winpos_flags(winpos->flags) );
1852
1853                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1854                  * in the high word for internal purposes
1855                  */
1856                 seq->wParam = winpos->flags & 0xffff;
1857                 /* We are not interested in the flags that don't match under XP and Win9x */
1858                 seq->wParam &= ~SWP_NOZORDER;
1859                 break;
1860             }
1861
1862             case WM_DRAWITEM:
1863             {
1864                 DRAW_ITEM_STRUCT di;
1865                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1866
1867                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1868                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1869                          dis->itemID, dis->itemAction, dis->itemState);
1870
1871                 di.u.lp = 0;
1872                 di.u.item.type = dis->CtlType;
1873                 di.u.item.ctl_id = dis->CtlID;
1874                 if (dis->CtlType == ODT_LISTBOX ||
1875                     dis->CtlType == ODT_COMBOBOX ||
1876                     dis->CtlType == ODT_MENU)
1877                     di.u.item.item_id = dis->itemID;
1878                 di.u.item.action = dis->itemAction;
1879                 di.u.item.state = dis->itemState;
1880
1881                 seq->lParam = di.u.lp;
1882                 break;
1883             }
1884             default:
1885                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1886                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1887                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1888             }
1889             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1890                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1891         }
1892     }
1893
1894     sequence_cnt++;
1895 }
1896
1897 /* try to make sure pending X events have been processed before continuing */
1898 static void flush_events(void)
1899 {
1900     MSG msg;
1901     int diff = 200;
1902     int min_timeout = 100;
1903     DWORD time = GetTickCount() + diff;
1904
1905     while (diff > 0)
1906     {
1907         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1908         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1909         diff = time - GetTickCount();
1910     }
1911 }
1912
1913 static void flush_sequence(void)
1914 {
1915     HeapFree(GetProcessHeap(), 0, sequence);
1916     sequence = 0;
1917     sequence_cnt = sequence_size = 0;
1918 }
1919
1920 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1921 {
1922     const struct recvd_message *actual = sequence;
1923     unsigned int count = 0;
1924
1925     trace_(file, line)("Failed sequence %s:\n", context );
1926     while (expected->message && actual->message)
1927     {
1928         if (actual->output[0])
1929         {
1930             if (expected->flags & hook)
1931             {
1932                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1933                                     count, expected->message, actual->output );
1934             }
1935             else if (expected->flags & winevent_hook)
1936             {
1937                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1938                                     count, expected->message, actual->output );
1939             }
1940             else
1941             {
1942                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1943                                     count, expected->message, actual->output );
1944             }
1945         }
1946
1947         if (expected->message == actual->message)
1948         {
1949             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1950                 (expected->flags & optional))
1951             {
1952                 /* don't match messages if their defwinproc status differs */
1953                 expected++;
1954             }
1955             else
1956             {
1957                 expected++;
1958                 actual++;
1959             }
1960         }
1961         /* silently drop winevent messages if there is no support for them */
1962         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1963             expected++;
1964         else
1965         {
1966             expected++;
1967             actual++;
1968         }
1969         count++;
1970     }
1971
1972     /* optional trailing messages */
1973     while (expected->message && ((expected->flags & optional) ||
1974             ((expected->flags & winevent_hook) && !hEvent_hook)))
1975     {
1976         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1977         expected++;
1978         count++;
1979     }
1980
1981     if (expected->message)
1982     {
1983         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1984         return;
1985     }
1986
1987     while (actual->message && actual->output[0])
1988     {
1989         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
1990         actual++;
1991         count++;
1992     }
1993 }
1994
1995 #define ok_sequence( exp, contx, todo) \
1996         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1997
1998
1999 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
2000                          const char *file, int line)
2001 {
2002     static const struct recvd_message end_of_sequence;
2003     const struct message *expected = expected_list;
2004     const struct recvd_message *actual;
2005     int failcount = 0, dump = 0;
2006     unsigned int count = 0;
2007
2008     add_message(&end_of_sequence);
2009
2010     actual = sequence;
2011
2012     while (expected->message && actual->message)
2013     {
2014         if (expected->message == actual->message)
2015         {
2016             if (expected->flags & wparam)
2017             {
2018                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2019                 {
2020                     todo_wine {
2021                         failcount ++;
2022                         if (strcmp(winetest_platform, "wine")) dump++;
2023                         ok_( file, line) (FALSE,
2024                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2025                             context, count, expected->message, expected->wParam, actual->wParam);
2026                     }
2027                 }
2028                 else
2029                 {
2030                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2031                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2032                                      context, count, expected->message, expected->wParam, actual->wParam);
2033                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2034                 }
2035
2036             }
2037             if (expected->flags & lparam)
2038             {
2039                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2040                 {
2041                     todo_wine {
2042                         failcount ++;
2043                         if (strcmp(winetest_platform, "wine")) dump++;
2044                         ok_( file, line) (FALSE,
2045                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2046                             context, count, expected->message, expected->lParam, actual->lParam);
2047                     }
2048                 }
2049                 else
2050                 {
2051                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2052                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2053                                      context, count, expected->message, expected->lParam, actual->lParam);
2054                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2055                 }
2056             }
2057             if ((expected->flags & optional) &&
2058                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2059             {
2060                 /* don't match optional messages if their defwinproc or parent status differs */
2061                 expected++;
2062                 count++;
2063                 continue;
2064             }
2065             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2066             {
2067                     todo_wine {
2068                         failcount ++;
2069                         if (strcmp(winetest_platform, "wine")) dump++;
2070                         ok_( file, line) (FALSE,
2071                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2072                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2073                     }
2074             }
2075             else
2076             {
2077                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2078                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2079                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2080                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2081             }
2082
2083             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2084                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2085                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2086             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2087
2088             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2089                 "%s: %u: the msg 0x%04x should have been %s\n",
2090                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2091             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2092
2093             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2094                 "%s: %u: the msg 0x%04x was expected in %s\n",
2095                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2096             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2097
2098             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2099                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2100                 context, count, expected->message);
2101             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2102
2103             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2104                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2105                 context, count, expected->message);
2106             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2107
2108             expected++;
2109             actual++;
2110         }
2111         /* silently drop hook messages if there is no support for them */
2112         else if ((expected->flags & optional) ||
2113                  ((expected->flags & hook) && !hCBT_hook) ||
2114                  ((expected->flags & winevent_hook) && !hEvent_hook))
2115             expected++;
2116         else if (todo)
2117         {
2118             failcount++;
2119             todo_wine {
2120                 if (strcmp(winetest_platform, "wine")) dump++;
2121                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2122                                   context, count, expected->message, actual->message);
2123             }
2124             goto done;
2125         }
2126         else
2127         {
2128             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2129                               context, count, expected->message, actual->message);
2130             dump++;
2131             expected++;
2132             actual++;
2133         }
2134         count++;
2135     }
2136
2137     /* skip all optional trailing messages */
2138     while (expected->message && ((expected->flags & optional) ||
2139                                  ((expected->flags & hook) && !hCBT_hook) ||
2140                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2141         expected++;
2142
2143     if (todo)
2144     {
2145         todo_wine {
2146             if (expected->message || actual->message) {
2147                 failcount++;
2148                 if (strcmp(winetest_platform, "wine")) dump++;
2149                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2150                                   context, count, expected->message, actual->message);
2151             }
2152         }
2153     }
2154     else
2155     {
2156         if (expected->message || actual->message)
2157         {
2158             dump++;
2159             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2160                               context, count, expected->message, actual->message);
2161         }
2162     }
2163     if( todo && !failcount) /* succeeded yet marked todo */
2164         todo_wine {
2165             if (!strcmp(winetest_platform, "wine")) dump++;
2166             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2167         }
2168
2169 done:
2170     if (dump) dump_sequence(expected_list, context, file, line);
2171     flush_sequence();
2172 }
2173
2174 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2175
2176 /******************************** MDI test **********************************/
2177
2178 /* CreateWindow for MDI frame window, initially visible */
2179 static const struct message WmCreateMDIframeSeq[] = {
2180     { HCBT_CREATEWND, hook },
2181     { WM_GETMINMAXINFO, sent },
2182     { WM_NCCREATE, sent },
2183     { WM_NCCALCSIZE, sent|wparam, 0 },
2184     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2185     { WM_CREATE, sent },
2186     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2187     { WM_NOTIFYFORMAT, sent|optional },
2188     { WM_QUERYUISTATE, sent|optional },
2189     { WM_WINDOWPOSCHANGING, sent|optional },
2190     { WM_GETMINMAXINFO, sent|optional },
2191     { WM_NCCALCSIZE, sent|optional },
2192     { WM_WINDOWPOSCHANGED, sent|optional },
2193     { WM_SHOWWINDOW, sent|wparam, 1 },
2194     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2195     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2196     { HCBT_ACTIVATE, hook },
2197     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2198     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2199     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2200     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2201     { WM_NCACTIVATE, sent },
2202     { WM_GETTEXT, sent|defwinproc|optional },
2203     { WM_ACTIVATE, sent|wparam, 1 },
2204     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2205     { HCBT_SETFOCUS, hook },
2206     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2207     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2208     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2209     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2210     /* Win9x adds SWP_NOZORDER below */
2211     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2212     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2213     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2214     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2215     { WM_MOVE, sent },
2216     { 0 }
2217 };
2218 /* DestroyWindow for MDI frame window, initially visible */
2219 static const struct message WmDestroyMDIframeSeq[] = {
2220     { HCBT_DESTROYWND, hook },
2221     { 0x0090, sent|optional },
2222     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2223     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2224     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2225     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2226     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2227     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2228     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2229     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2230     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2231     { WM_DESTROY, sent },
2232     { WM_NCDESTROY, sent },
2233     { 0 }
2234 };
2235 /* CreateWindow for MDI client window, initially visible */
2236 static const struct message WmCreateMDIclientSeq[] = {
2237     { HCBT_CREATEWND, hook },
2238     { WM_NCCREATE, sent },
2239     { WM_NCCALCSIZE, sent|wparam, 0 },
2240     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2241     { WM_CREATE, sent },
2242     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2243     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2244     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2245     { WM_MOVE, sent },
2246     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2247     { WM_SHOWWINDOW, sent|wparam, 1 },
2248     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2249     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2250     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2251     { 0 }
2252 };
2253 /* ShowWindow(SW_SHOW) for MDI client window */
2254 static const struct message WmShowMDIclientSeq[] = {
2255     { WM_SHOWWINDOW, sent|wparam, 1 },
2256     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2257     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2258     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2259     { 0 }
2260 };
2261 /* ShowWindow(SW_HIDE) for MDI client window */
2262 static const struct message WmHideMDIclientSeq[] = {
2263     { WM_SHOWWINDOW, sent|wparam, 0 },
2264     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2265     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2266     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2267     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2268     { 0 }
2269 };
2270 /* DestroyWindow for MDI client window, initially visible */
2271 static const struct message WmDestroyMDIclientSeq[] = {
2272     { HCBT_DESTROYWND, hook },
2273     { 0x0090, sent|optional },
2274     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2275     { WM_SHOWWINDOW, sent|wparam, 0 },
2276     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2277     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2278     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2279     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2280     { WM_DESTROY, sent },
2281     { WM_NCDESTROY, sent },
2282     { 0 }
2283 };
2284 /* CreateWindow for MDI child window, initially visible */
2285 static const struct message WmCreateMDIchildVisibleSeq[] = {
2286     { HCBT_CREATEWND, hook },
2287     { WM_NCCREATE, sent }, 
2288     { WM_NCCALCSIZE, sent|wparam, 0 },
2289     { WM_CREATE, sent },
2290     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2291     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2292     { WM_MOVE, sent },
2293     /* Win2k sends wparam set to
2294      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2295      * while Win9x doesn't bother to set child window id according to
2296      * CLIENTCREATESTRUCT.idFirstChild
2297      */
2298     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2299     { WM_SHOWWINDOW, sent|wparam, 1 },
2300     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2301     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2302     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2303     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2304     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2305     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2306     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2307
2308     /* Win9x: message sequence terminates here. */
2309
2310     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2311     { HCBT_SETFOCUS, hook }, /* in MDI client */
2312     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2313     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2314     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2315     { WM_SETFOCUS, sent }, /* in MDI client */
2316     { HCBT_SETFOCUS, hook },
2317     { WM_KILLFOCUS, sent }, /* in MDI client */
2318     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2319     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2320     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2321     { WM_SETFOCUS, sent|defwinproc },
2322     { WM_MDIACTIVATE, sent|defwinproc },
2323     { 0 }
2324 };
2325 /* CreateWindow for MDI child window with invisible parent */
2326 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2327     { HCBT_CREATEWND, hook },
2328     { WM_GETMINMAXINFO, sent },
2329     { WM_NCCREATE, sent }, 
2330     { WM_NCCALCSIZE, sent|wparam, 0 },
2331     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2332     { WM_CREATE, sent },
2333     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2334     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2335     { WM_MOVE, sent },
2336     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2337     { WM_SHOWWINDOW, sent|wparam, 1 },
2338     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2339     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2340     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2341     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2342
2343     /* Win9x: message sequence terminates here. */
2344
2345     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2346     { HCBT_SETFOCUS, hook }, /* in MDI client */
2347     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2348     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2349     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2350     { WM_SETFOCUS, sent }, /* in MDI client */
2351     { HCBT_SETFOCUS, hook },
2352     { WM_KILLFOCUS, sent }, /* in MDI client */
2353     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2354     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2355     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2356     { WM_SETFOCUS, sent|defwinproc },
2357     { WM_MDIACTIVATE, sent|defwinproc },
2358     { 0 }
2359 };
2360 /* DestroyWindow for MDI child window, initially visible */
2361 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2362     { HCBT_DESTROYWND, hook },
2363     /* Win2k sends wparam set to
2364      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2365      * while Win9x doesn't bother to set child window id according to
2366      * CLIENTCREATESTRUCT.idFirstChild
2367      */
2368     { 0x0090, sent|optional },
2369     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2370     { WM_SHOWWINDOW, sent|wparam, 0 },
2371     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2372     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2373     { WM_ERASEBKGND, sent|parent|optional },
2374     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2375
2376     /* { WM_DESTROY, sent }
2377      * Win9x: message sequence terminates here.
2378      */
2379
2380     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2381     { WM_KILLFOCUS, sent },
2382     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2383     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2384     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2385     { WM_SETFOCUS, sent }, /* in MDI client */
2386
2387     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2388     { WM_KILLFOCUS, sent }, /* in MDI client */
2389     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2390     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2391     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2392     { WM_SETFOCUS, sent }, /* in MDI client */
2393
2394     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2395
2396     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2397     { WM_KILLFOCUS, sent },
2398     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2399     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2400     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2401     { WM_SETFOCUS, sent }, /* in MDI client */
2402
2403     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2404     { WM_KILLFOCUS, sent }, /* in MDI client */
2405     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2406     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2407     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2408     { WM_SETFOCUS, sent }, /* in MDI client */
2409
2410     { WM_DESTROY, sent },
2411
2412     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2413     { WM_KILLFOCUS, sent },
2414     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2415     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2416     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2417     { WM_SETFOCUS, sent }, /* in MDI client */
2418
2419     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2420     { WM_KILLFOCUS, sent }, /* in MDI client */
2421     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2422     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2423     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2424     { WM_SETFOCUS, sent }, /* in MDI client */
2425
2426     { WM_NCDESTROY, sent },
2427     { 0 }
2428 };
2429 /* CreateWindow for MDI child window, initially invisible */
2430 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2431     { HCBT_CREATEWND, hook },
2432     { WM_NCCREATE, sent }, 
2433     { WM_NCCALCSIZE, sent|wparam, 0 },
2434     { WM_CREATE, sent },
2435     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2436     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2437     { WM_MOVE, sent },
2438     /* Win2k sends wparam set to
2439      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2440      * while Win9x doesn't bother to set child window id according to
2441      * CLIENTCREATESTRUCT.idFirstChild
2442      */
2443     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2444     { 0 }
2445 };
2446 /* DestroyWindow for MDI child window, initially invisible */
2447 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2448     { HCBT_DESTROYWND, hook },
2449     /* Win2k sends wparam set to
2450      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2451      * while Win9x doesn't bother to set child window id according to
2452      * CLIENTCREATESTRUCT.idFirstChild
2453      */
2454     { 0x0090, sent|optional },
2455     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2456     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2457     { WM_DESTROY, sent },
2458     { WM_NCDESTROY, sent },
2459     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2460     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2461     { 0 }
2462 };
2463 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2464 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2465     { HCBT_CREATEWND, hook },
2466     { WM_NCCREATE, sent }, 
2467     { WM_NCCALCSIZE, sent|wparam, 0 },
2468     { WM_CREATE, sent },
2469     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2470     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2471     { WM_MOVE, sent },
2472     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2473     { WM_GETMINMAXINFO, sent },
2474     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2475     { WM_NCCALCSIZE, sent|wparam, 1 },
2476     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2477     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2478      /* in MDI frame */
2479     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2480     { WM_NCCALCSIZE, sent|wparam, 1 },
2481     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2482     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2483     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2484     /* Win2k sends wparam set to
2485      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2486      * while Win9x doesn't bother to set child window id according to
2487      * CLIENTCREATESTRUCT.idFirstChild
2488      */
2489     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2490     { WM_SHOWWINDOW, sent|wparam, 1 },
2491     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2492     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2494     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2495     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2496     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2497     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2498
2499     /* Win9x: message sequence terminates here. */
2500
2501     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2502     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2503     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2504     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2505     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2506     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2507     { HCBT_SETFOCUS, hook|optional },
2508     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2509     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2510     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2511     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2512     { WM_SETFOCUS, sent|defwinproc|optional },
2513     { WM_MDIACTIVATE, sent|defwinproc|optional },
2514      /* in MDI frame */
2515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2516     { WM_NCCALCSIZE, sent|wparam, 1 },
2517     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2518     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2519     { 0 }
2520 };
2521 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2522 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2523     /* restore the 1st MDI child */
2524     { WM_SETREDRAW, sent|wparam, 0 },
2525     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2526     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2527     { WM_NCCALCSIZE, sent|wparam, 1 },
2528     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2529     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2530     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2531      /* in MDI frame */
2532     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2533     { WM_NCCALCSIZE, sent|wparam, 1 },
2534     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2535     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2536     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2537     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2538     /* create the 2nd MDI child */
2539     { HCBT_CREATEWND, hook },
2540     { WM_NCCREATE, sent }, 
2541     { WM_NCCALCSIZE, sent|wparam, 0 },
2542     { WM_CREATE, sent },
2543     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2544     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2545     { WM_MOVE, sent },
2546     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2547     { WM_GETMINMAXINFO, sent },
2548     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2549     { WM_NCCALCSIZE, sent|wparam, 1 },
2550     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2551     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2552     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2553      /* in MDI frame */
2554     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2555     { WM_NCCALCSIZE, sent|wparam, 1 },
2556     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2557     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2558     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2559     /* Win2k sends wparam set to
2560      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2561      * while Win9x doesn't bother to set child window id according to
2562      * CLIENTCREATESTRUCT.idFirstChild
2563      */
2564     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2565     { WM_SHOWWINDOW, sent|wparam, 1 },
2566     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2567     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2568     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2569     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2570     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2571     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2572
2573     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2574     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2575
2576     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2577
2578     /* Win9x: message sequence terminates here. */
2579
2580     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2581     { HCBT_SETFOCUS, hook },
2582     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2583     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2584     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2585     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2586     { WM_SETFOCUS, sent }, /* in MDI client */
2587     { HCBT_SETFOCUS, hook },
2588     { WM_KILLFOCUS, sent }, /* in MDI client */
2589     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2590     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2591     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2592     { WM_SETFOCUS, sent|defwinproc },
2593
2594     { WM_MDIACTIVATE, sent|defwinproc },
2595      /* in MDI frame */
2596     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2597     { WM_NCCALCSIZE, sent|wparam, 1 },
2598     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2599     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2600     { 0 }
2601 };
2602 /* WM_MDICREATE MDI child window, initially visible and maximized */
2603 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2604     { WM_MDICREATE, sent },
2605     { HCBT_CREATEWND, hook },
2606     { WM_NCCREATE, sent }, 
2607     { WM_NCCALCSIZE, sent|wparam, 0 },
2608     { WM_CREATE, sent },
2609     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2610     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2611     { WM_MOVE, sent },
2612     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2613     { WM_GETMINMAXINFO, sent },
2614     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2615     { WM_NCCALCSIZE, sent|wparam, 1 },
2616     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2617     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2618
2619      /* in MDI frame */
2620     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2621     { WM_NCCALCSIZE, sent|wparam, 1 },
2622     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2623     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2624     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2625
2626     /* Win2k sends wparam set to
2627      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2628      * while Win9x doesn't bother to set child window id according to
2629      * CLIENTCREATESTRUCT.idFirstChild
2630      */
2631     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2632     { WM_SHOWWINDOW, sent|wparam, 1 },
2633     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2634
2635     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2636
2637     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2638     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2639     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2640
2641     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2642     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2643
2644     /* Win9x: message sequence terminates here. */
2645
2646     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2647     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2648     { HCBT_SETFOCUS, hook }, /* in MDI client */
2649     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2650     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2651     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2652     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2653     { HCBT_SETFOCUS, hook|optional },
2654     { WM_KILLFOCUS, sent }, /* in MDI client */
2655     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2656     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2657     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2658     { WM_SETFOCUS, sent|defwinproc },
2659
2660     { WM_MDIACTIVATE, sent|defwinproc },
2661
2662      /* in MDI child */
2663     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2664     { WM_NCCALCSIZE, sent|wparam, 1 },
2665     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2666     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2667
2668      /* in MDI frame */
2669     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2670     { WM_NCCALCSIZE, sent|wparam, 1 },
2671     { 0x0093, sent|defwinproc|optional },
2672     { 0x0093, sent|defwinproc|optional },
2673     { 0x0093, sent|defwinproc|optional },
2674     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2675     { WM_MOVE, sent|defwinproc },
2676     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2677
2678      /* in MDI client */
2679     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2680     { WM_NCCALCSIZE, sent|wparam, 1 },
2681     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2682     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2683
2684      /* in MDI child */
2685     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2686     { WM_NCCALCSIZE, sent|wparam, 1 },
2687     { 0x0093, sent|optional },
2688     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2689     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2690
2691     { 0x0093, sent|optional },
2692     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2693     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2694     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2695     { 0x0093, sent|defwinproc|optional },
2696     { 0x0093, sent|defwinproc|optional },
2697     { 0x0093, sent|defwinproc|optional },
2698     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2699     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2700
2701     { 0 }
2702 };
2703 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2704 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2705     { HCBT_CREATEWND, hook },
2706     { WM_GETMINMAXINFO, sent },
2707     { WM_NCCREATE, sent }, 
2708     { WM_NCCALCSIZE, sent|wparam, 0 },
2709     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2710     { WM_CREATE, sent },
2711     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2712     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2713     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2714     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2715     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2716     { WM_MOVE, sent },
2717     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2718     { WM_GETMINMAXINFO, sent },
2719     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2720     { WM_GETMINMAXINFO, sent|defwinproc },
2721     { WM_NCCALCSIZE, sent|wparam, 1 },
2722     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2723     { WM_MOVE, sent|defwinproc },
2724     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2725      /* in MDI frame */
2726     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2727     { WM_NCCALCSIZE, sent|wparam, 1 },
2728     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2729     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2730     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2731     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2732     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2733     /* Win2k sends wparam set to
2734      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2735      * while Win9x doesn't bother to set child window id according to
2736      * CLIENTCREATESTRUCT.idFirstChild
2737      */
2738     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2739     { 0 }
2740 };
2741 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2742 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2743     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2744     { HCBT_SYSCOMMAND, hook },
2745     { WM_CLOSE, sent|defwinproc },
2746     { WM_MDIDESTROY, sent }, /* in MDI client */
2747
2748     /* bring the 1st MDI child to top */
2749     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2750     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2751
2752     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2753
2754     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2755     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2756     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2757
2758     /* maximize the 1st MDI child */
2759     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2760     { WM_GETMINMAXINFO, sent|defwinproc },
2761     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2762     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2763     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2764     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2765     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2766
2767     /* restore the 2nd MDI child */
2768     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2769     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2770     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2771     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2772
2773     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2774
2775     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2776     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2777
2778     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2779
2780     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2781      /* in MDI frame */
2782     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2783     { WM_NCCALCSIZE, sent|wparam, 1 },
2784     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2785     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2786     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2787
2788     /* bring the 1st MDI child to top */
2789     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2790     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2791     { HCBT_SETFOCUS, hook },
2792     { WM_KILLFOCUS, sent|defwinproc },
2793     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2794     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2795     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2796     { WM_SETFOCUS, sent }, /* in MDI client */
2797     { HCBT_SETFOCUS, hook },
2798     { WM_KILLFOCUS, sent }, /* in MDI client */
2799     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2800     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2801     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2802     { WM_SETFOCUS, sent|defwinproc },
2803     { WM_MDIACTIVATE, sent|defwinproc },
2804     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2805
2806     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2807     { WM_SHOWWINDOW, sent|wparam, 1 },
2808     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2809     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2810     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2811     { WM_MDIREFRESHMENU, sent },
2812
2813     { HCBT_DESTROYWND, hook },
2814     /* Win2k sends wparam set to
2815      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2816      * while Win9x doesn't bother to set child window id according to
2817      * CLIENTCREATESTRUCT.idFirstChild
2818      */
2819     { 0x0090, sent|defwinproc|optional },
2820     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2821     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2822     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2823     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2824     { WM_ERASEBKGND, sent|parent|optional },
2825     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2826
2827     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2828     { WM_DESTROY, sent|defwinproc },
2829     { WM_NCDESTROY, sent|defwinproc },
2830     { 0 }
2831 };
2832 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2833 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2834     { WM_MDIDESTROY, sent }, /* in MDI client */
2835     { WM_SHOWWINDOW, sent|wparam, 0 },
2836     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2837     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2838     { WM_ERASEBKGND, sent|parent|optional },
2839     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2840
2841     { HCBT_SETFOCUS, hook },
2842     { WM_KILLFOCUS, sent },
2843     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2844     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2845     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2846     { WM_SETFOCUS, sent }, /* in MDI client */
2847     { HCBT_SETFOCUS, hook },
2848     { WM_KILLFOCUS, sent }, /* in MDI client */
2849     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2850     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2851     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2852     { WM_SETFOCUS, sent },
2853
2854      /* in MDI child */
2855     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2856     { WM_NCCALCSIZE, sent|wparam, 1 },
2857     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2858     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2859
2860      /* in MDI frame */
2861     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2862     { WM_NCCALCSIZE, sent|wparam, 1 },
2863     { 0x0093, sent|defwinproc|optional },
2864     { 0x0093, sent|defwinproc|optional },
2865     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2866     { WM_MOVE, sent|defwinproc },
2867     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2868
2869      /* in MDI client */
2870     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2871     { WM_NCCALCSIZE, sent|wparam, 1 },
2872     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2873     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2874
2875      /* in MDI child */
2876     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2877     { WM_NCCALCSIZE, sent|wparam, 1 },
2878     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2879     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2880
2881      /* in MDI child */
2882     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2883     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2884     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2885     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2886
2887      /* in MDI frame */
2888     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2889     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2890     { 0x0093, sent|defwinproc|optional },
2891     { 0x0093, sent|defwinproc|optional },
2892     { 0x0093, sent|defwinproc|optional },
2893     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2894     { WM_MOVE, sent|defwinproc },
2895     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2896
2897      /* in MDI client */
2898     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2899     { WM_NCCALCSIZE, sent|wparam, 1 },
2900     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2901     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2902
2903      /* in MDI child */
2904     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2905     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2906     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2907     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2908     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2909     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2910
2911     { 0x0093, sent|defwinproc|optional },
2912     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2913     { 0x0093, sent|defwinproc|optional },
2914     { 0x0093, sent|defwinproc|optional },
2915     { 0x0093, sent|defwinproc|optional },
2916     { 0x0093, sent|optional },
2917
2918     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2919     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2920     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2921     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2922     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2923
2924      /* in MDI frame */
2925     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2926     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2927     { 0x0093, sent|defwinproc|optional },
2928     { 0x0093, sent|defwinproc|optional },
2929     { 0x0093, sent|defwinproc|optional },
2930     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2931     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2932     { 0x0093, sent|optional },
2933
2934     { WM_NCACTIVATE, sent|wparam, 0 },
2935     { WM_MDIACTIVATE, sent },
2936
2937     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2938     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2939     { WM_NCCALCSIZE, sent|wparam, 1 },
2940
2941     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2942
2943     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2944     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2945     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2946
2947      /* in MDI child */
2948     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2949     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2950     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2951     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2952
2953      /* in MDI frame */
2954     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2955     { WM_NCCALCSIZE, sent|wparam, 1 },
2956     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2957     { WM_MOVE, sent|defwinproc },
2958     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2959
2960      /* in MDI client */
2961     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2962     { WM_NCCALCSIZE, sent|wparam, 1 },
2963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2964     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2965     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2966     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2967     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2968     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2969     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2970
2971     { HCBT_SETFOCUS, hook },
2972     { WM_KILLFOCUS, sent },
2973     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2974     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2975     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2976     { WM_SETFOCUS, sent }, /* in MDI client */
2977
2978     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2979
2980     { HCBT_DESTROYWND, hook },
2981     /* Win2k sends wparam set to
2982      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2983      * while Win9x doesn't bother to set child window id according to
2984      * CLIENTCREATESTRUCT.idFirstChild
2985      */
2986     { 0x0090, sent|optional },
2987     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2988
2989     { WM_SHOWWINDOW, sent|wparam, 0 },
2990     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2991     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2992     { WM_ERASEBKGND, sent|parent|optional },
2993     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2994
2995     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2996     { WM_DESTROY, sent },
2997     { WM_NCDESTROY, sent },
2998     { 0 }
2999 };
3000 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3001 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3002     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3003     { WM_GETMINMAXINFO, sent },
3004     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3005     { WM_NCCALCSIZE, sent|wparam, 1 },
3006     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3007     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3008
3009     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3010     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3011     { HCBT_SETFOCUS, hook|optional },
3012     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3013     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3014     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3015     { HCBT_SETFOCUS, hook|optional },
3016     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3017     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3018     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3019     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3020     { WM_SETFOCUS, sent|optional|defwinproc },
3021     { WM_MDIACTIVATE, sent|optional|defwinproc },
3022     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3023     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3024      /* in MDI frame */
3025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3026     { WM_NCCALCSIZE, sent|wparam, 1 },
3027     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3028     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3029     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3030     { 0 }
3031 };
3032 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3033 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3034     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3035     { WM_GETMINMAXINFO, sent },
3036     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3037     { WM_GETMINMAXINFO, sent|defwinproc },
3038     { WM_NCCALCSIZE, sent|wparam, 1 },
3039     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3040     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3041
3042     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3043     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3044     { HCBT_SETFOCUS, hook|optional },
3045     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3046     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3047     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3048     { HCBT_SETFOCUS, hook|optional },
3049     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3050     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3051     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3052     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3053     { WM_SETFOCUS, sent|defwinproc|optional },
3054     { WM_MDIACTIVATE, sent|defwinproc|optional },
3055     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3056     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3057     { 0 }
3058 };
3059 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3060 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3061     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3062     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3063     { WM_GETMINMAXINFO, sent },
3064     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3065     { WM_GETMINMAXINFO, sent|defwinproc },
3066     { WM_NCCALCSIZE, sent|wparam, 1 },
3067     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3068     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3069     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3070     { WM_MOVE, sent|defwinproc },
3071     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3072
3073     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3074     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3075     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3076     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3077     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3078     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3079      /* in MDI frame */
3080     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3081     { WM_NCCALCSIZE, sent|wparam, 1 },
3082     { 0x0093, sent|defwinproc|optional },
3083     { 0x0094, sent|defwinproc|optional },
3084     { 0x0094, sent|defwinproc|optional },
3085     { 0x0094, sent|defwinproc|optional },
3086     { 0x0094, sent|defwinproc|optional },
3087     { 0x0093, sent|defwinproc|optional },
3088     { 0x0093, sent|defwinproc|optional },
3089     { 0x0091, sent|defwinproc|optional },
3090     { 0x0092, sent|defwinproc|optional },
3091     { 0x0092, sent|defwinproc|optional },
3092     { 0x0092, sent|defwinproc|optional },
3093     { 0x0092, sent|defwinproc|optional },
3094     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3095     { WM_MOVE, sent|defwinproc },
3096     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3097     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3098      /* in MDI client */
3099     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3100     { WM_NCCALCSIZE, sent|wparam, 1 },
3101     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3102     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3103      /* in MDI child */
3104     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3105     { WM_GETMINMAXINFO, sent|defwinproc },
3106     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3107     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3108     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3109     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3110     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3111     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3112     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3113     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3114      /* in MDI frame */
3115     { 0x0093, sent|optional },
3116     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3117     { 0x0093, sent|defwinproc|optional },
3118     { 0x0093, sent|defwinproc|optional },
3119     { 0x0093, sent|defwinproc|optional },
3120     { 0x0091, sent|defwinproc|optional },
3121     { 0x0092, sent|defwinproc|optional },
3122     { 0x0092, sent|defwinproc|optional },
3123     { 0x0092, sent|defwinproc|optional },
3124     { 0x0092, sent|defwinproc|optional },
3125     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3126     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3127     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3128     { 0 }
3129 };
3130 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3131 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3132     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3133     { WM_GETMINMAXINFO, sent },
3134     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3135     { WM_NCCALCSIZE, sent|wparam, 1 },
3136     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3137     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3138     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3139      /* in MDI frame */
3140     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3141     { WM_NCCALCSIZE, sent|wparam, 1 },
3142     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3143     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3144     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3145     { 0 }
3146 };
3147 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3148 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3149     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3150     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3151     { WM_NCCALCSIZE, sent|wparam, 1 },
3152     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3153     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3154     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3155      /* in MDI frame */
3156     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3157     { WM_NCCALCSIZE, sent|wparam, 1 },
3158     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3159     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3160     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3161     { 0 }
3162 };
3163 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3164 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3165     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3166     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3167     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3168     { WM_NCCALCSIZE, sent|wparam, 1 },
3169     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3170     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3171     { WM_MOVE, sent|defwinproc },
3172     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3173     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3174     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3175     { HCBT_SETFOCUS, hook },
3176     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3177     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3178     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3179     { WM_SETFOCUS, sent },
3180     { 0 }
3181 };
3182 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3183 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3184     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3185     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3186     { WM_NCCALCSIZE, sent|wparam, 1 },
3187     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3188     { WM_MOVE, sent|defwinproc },
3189     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
3190     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3191     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3192     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3193     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3194     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3195     { 0 }
3196 };
3197 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3198 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3199     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3200     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3201     { WM_NCCALCSIZE, sent|wparam, 1 },
3202     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3203     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3204     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3205     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3206      /* in MDI frame */
3207     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3208     { WM_NCCALCSIZE, sent|wparam, 1 },
3209     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3210     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3211     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3212     { 0 }
3213 };
3214
3215 static HWND mdi_client;
3216 static WNDPROC old_mdi_client_proc;
3217
3218 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3219 {
3220     struct recvd_message msg;
3221
3222     /* do not log painting messages */
3223     if (message != WM_PAINT &&
3224         message != WM_NCPAINT &&
3225         message != WM_SYNCPAINT &&
3226         message != WM_ERASEBKGND &&
3227         message != WM_NCHITTEST &&
3228         message != WM_GETTEXT &&
3229         message != WM_MDIGETACTIVE &&
3230         !ignore_message( message ))
3231     {
3232         msg.hwnd = hwnd;
3233         msg.message = message;
3234         msg.flags = sent|wparam|lparam;
3235         msg.wParam = wParam;
3236         msg.lParam = lParam;
3237         msg.descr = "mdi client";
3238         add_message(&msg);
3239     }
3240
3241     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3242 }
3243
3244 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3245 {
3246     static LONG defwndproc_counter = 0;
3247     LRESULT ret;
3248     struct recvd_message msg;
3249
3250     /* do not log painting messages */
3251     if (message != WM_PAINT &&
3252         message != WM_NCPAINT &&
3253         message != WM_SYNCPAINT &&
3254         message != WM_ERASEBKGND &&
3255         message != WM_NCHITTEST &&
3256         message != WM_GETTEXT &&
3257         !ignore_message( message ))
3258     {
3259         switch (message)
3260         {
3261             case WM_MDIACTIVATE:
3262             {
3263                 HWND active, client = GetParent(hwnd);
3264
3265                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3266
3267                 if (hwnd == (HWND)lParam) /* if we are being activated */
3268                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3269                 else
3270                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3271                 break;
3272             }
3273         }
3274
3275         msg.hwnd = hwnd;
3276         msg.message = message;
3277         msg.flags = sent|wparam|lparam;
3278         if (defwndproc_counter) msg.flags |= defwinproc;
3279         msg.wParam = wParam;
3280         msg.lParam = lParam;
3281         msg.descr = "mdi child";
3282         add_message(&msg);
3283     }
3284
3285     defwndproc_counter++;
3286     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3287     defwndproc_counter--;
3288
3289     return ret;
3290 }
3291
3292 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3293 {
3294     static LONG defwndproc_counter = 0;
3295     LRESULT ret;
3296     struct recvd_message msg;
3297
3298     /* do not log painting messages */
3299     if (message != WM_PAINT &&
3300         message != WM_NCPAINT &&
3301         message != WM_SYNCPAINT &&
3302         message != WM_ERASEBKGND &&
3303         message != WM_NCHITTEST &&
3304         message != WM_GETTEXT &&
3305         !ignore_message( message ))
3306     {
3307         msg.hwnd = hwnd;
3308         msg.message = message;
3309         msg.flags = sent|wparam|lparam;
3310         if (defwndproc_counter) msg.flags |= defwinproc;
3311         msg.wParam = wParam;
3312         msg.lParam = lParam;
3313         msg.descr = "mdi frame";
3314         add_message(&msg);
3315     }
3316
3317     defwndproc_counter++;
3318     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3319     defwndproc_counter--;
3320
3321     return ret;
3322 }
3323
3324 static BOOL mdi_RegisterWindowClasses(void)
3325 {
3326     WNDCLASSA cls;
3327
3328     cls.style = 0;
3329     cls.lpfnWndProc = mdi_frame_wnd_proc;
3330     cls.cbClsExtra = 0;
3331     cls.cbWndExtra = 0;
3332     cls.hInstance = GetModuleHandleA(0);
3333     cls.hIcon = 0;
3334     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3335     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3336     cls.lpszMenuName = NULL;
3337     cls.lpszClassName = "MDI_frame_class";
3338     if (!RegisterClassA(&cls)) return FALSE;
3339
3340     cls.lpfnWndProc = mdi_child_wnd_proc;
3341     cls.lpszClassName = "MDI_child_class";
3342     if (!RegisterClassA(&cls)) return FALSE;
3343
3344     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3345     old_mdi_client_proc = cls.lpfnWndProc;
3346     cls.hInstance = GetModuleHandleA(0);
3347     cls.lpfnWndProc = mdi_client_hook_proc;
3348     cls.lpszClassName = "MDI_client_class";
3349     if (!RegisterClassA(&cls)) assert(0);
3350
3351     return TRUE;
3352 }
3353
3354 static void test_mdi_messages(void)
3355 {
3356     MDICREATESTRUCTA mdi_cs;
3357     CLIENTCREATESTRUCT client_cs;
3358     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3359     BOOL zoomed;
3360     HMENU hMenu = CreateMenu();
3361
3362     assert(mdi_RegisterWindowClasses());
3363
3364     flush_sequence();
3365
3366     trace("creating MDI frame window\n");
3367     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3368                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3369                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3370                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3371                                 GetDesktopWindow(), hMenu,
3372                                 GetModuleHandleA(0), NULL);
3373     assert(mdi_frame);
3374     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3375
3376     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3377     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3378
3379     trace("creating MDI client window\n");
3380     client_cs.hWindowMenu = 0;
3381     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3382     mdi_client = CreateWindowExA(0, "MDI_client_class",
3383                                  NULL,
3384                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3385                                  0, 0, 0, 0,
3386                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3387     assert(mdi_client);
3388     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3389
3390     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3391     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3392
3393     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3394     ok(!active_child, "wrong active MDI child %p\n", active_child);
3395     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3396
3397     SetFocus(0);
3398     flush_sequence();
3399
3400     trace("creating invisible MDI child window\n");
3401     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3402                                 WS_CHILD,
3403                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3404                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3405     assert(mdi_child);
3406
3407     flush_sequence();
3408     ShowWindow(mdi_child, SW_SHOWNORMAL);
3409     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3410
3411     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3412     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3413
3414     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3415     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3416
3417     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3418     ok(!active_child, "wrong active MDI child %p\n", active_child);
3419     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3420
3421     ShowWindow(mdi_child, SW_HIDE);
3422     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3423     flush_sequence();
3424
3425     ShowWindow(mdi_child, SW_SHOW);
3426     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3427
3428     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3429     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3430
3431     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3432     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3433
3434     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3435     ok(!active_child, "wrong active MDI child %p\n", active_child);
3436     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3437
3438     DestroyWindow(mdi_child);
3439     flush_sequence();
3440
3441     trace("creating visible MDI child window\n");
3442     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3443                                 WS_CHILD | WS_VISIBLE,
3444                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3445                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3446     assert(mdi_child);
3447     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3448
3449     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3450     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3451
3452     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3453     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3454
3455     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3456     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3457     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3458     flush_sequence();
3459
3460     DestroyWindow(mdi_child);
3461     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3462
3463     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3464     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3465
3466     /* Win2k: MDI client still returns a just destroyed child as active
3467      * Win9x: MDI client returns 0
3468      */
3469     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3470     ok(active_child == mdi_child || /* win2k */
3471        !active_child, /* win9x */
3472        "wrong active MDI child %p\n", active_child);
3473     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3474
3475     flush_sequence();
3476
3477     trace("creating invisible MDI child window\n");
3478     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3479                                 WS_CHILD,
3480                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3481                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3482     assert(mdi_child2);
3483     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3484
3485     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3486     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3487
3488     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3489     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3490
3491     /* Win2k: MDI client still returns a just destroyed child as active
3492      * Win9x: MDI client returns mdi_child2
3493      */
3494     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3495     ok(active_child == mdi_child || /* win2k */
3496        active_child == mdi_child2, /* win9x */
3497        "wrong active MDI child %p\n", active_child);
3498     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3499     flush_sequence();
3500
3501     ShowWindow(mdi_child2, SW_MAXIMIZE);
3502     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3503
3504     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3505     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3506
3507     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3508     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3509     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3510     flush_sequence();
3511
3512     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3513     ok(GetFocus() == mdi_child2 || /* win2k */
3514        GetFocus() == 0, /* win9x */
3515        "wrong focus window %p\n", GetFocus());
3516
3517     SetFocus(0);
3518     flush_sequence();
3519
3520     ShowWindow(mdi_child2, SW_HIDE);
3521     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3522
3523     ShowWindow(mdi_child2, SW_RESTORE);
3524     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3525     flush_sequence();
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     SetFocus(0);
3536     flush_sequence();
3537
3538     ShowWindow(mdi_child2, SW_HIDE);
3539     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3540
3541     ShowWindow(mdi_child2, SW_SHOW);
3542     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3543
3544     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3545     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3546
3547     ShowWindow(mdi_child2, SW_MAXIMIZE);
3548     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3549
3550     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3551     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3552
3553     ShowWindow(mdi_child2, SW_RESTORE);
3554     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3555
3556     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3557     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3558
3559     ShowWindow(mdi_child2, SW_MINIMIZE);
3560     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3561
3562     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3563     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3564
3565     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3566     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3567     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3568     flush_sequence();
3569
3570     ShowWindow(mdi_child2, SW_RESTORE);
3571     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3572
3573     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3574     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3575
3576     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3577     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3578     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3579     flush_sequence();
3580
3581     SetFocus(0);
3582     flush_sequence();
3583
3584     ShowWindow(mdi_child2, SW_HIDE);
3585     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3586
3587     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3588     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3589
3590     DestroyWindow(mdi_child2);
3591     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3592
3593     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3594     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3595
3596     /* test for maximized MDI children */
3597     trace("creating maximized visible MDI child window 1\n");
3598     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3599                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3600                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3601                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3602     assert(mdi_child);
3603     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3604     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3605
3606     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3607     ok(GetFocus() == mdi_child || /* win2k */
3608        GetFocus() == 0, /* win9x */
3609        "wrong focus window %p\n", GetFocus());
3610
3611     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3612     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3613     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3614     flush_sequence();
3615
3616     trace("creating maximized visible MDI child window 2\n");
3617     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3618                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3619                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3620                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3621     assert(mdi_child2);
3622     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3623     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3624     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3625
3626     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3627     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3628
3629     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3630     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3631     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3632     flush_sequence();
3633
3634     trace("destroying maximized visible MDI child window 2\n");
3635     DestroyWindow(mdi_child2);
3636     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3637
3638     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3639
3640     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3641     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3642
3643     /* Win2k: MDI client still returns a just destroyed child as active
3644      * Win9x: MDI client returns 0
3645      */
3646     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3647     ok(active_child == mdi_child2 || /* win2k */
3648        !active_child, /* win9x */
3649        "wrong active MDI child %p\n", active_child);
3650     flush_sequence();
3651
3652     ShowWindow(mdi_child, SW_MAXIMIZE);
3653     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3654     flush_sequence();
3655
3656     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3657     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3658
3659     trace("re-creating maximized visible MDI child window 2\n");
3660     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3661                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3662                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3663                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3664     assert(mdi_child2);
3665     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3666     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3667     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3668
3669     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3670     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3671
3672     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3673     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3674     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3675     flush_sequence();
3676
3677     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3678     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3679     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3680
3681     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3682     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3683     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3684
3685     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3686     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3687     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3688     flush_sequence();
3689
3690     DestroyWindow(mdi_child);
3691     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3692
3693     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3694     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3695
3696     /* Win2k: MDI client still returns a just destroyed child as active
3697      * Win9x: MDI client returns 0
3698      */
3699     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3700     ok(active_child == mdi_child || /* win2k */
3701        !active_child, /* win9x */
3702        "wrong active MDI child %p\n", active_child);
3703     flush_sequence();
3704
3705     trace("creating maximized invisible MDI child window\n");
3706     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3707                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3708                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3709                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3710     assert(mdi_child2);
3711     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3712     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3713     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3714     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3715
3716     /* Win2k: MDI client still returns a just destroyed child as active
3717      * Win9x: MDI client returns 0
3718      */
3719     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3720     ok(active_child == mdi_child || /* win2k */
3721        !active_child || active_child == mdi_child2, /* win9x */
3722        "wrong active MDI child %p\n", active_child);
3723     flush_sequence();
3724
3725     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3726     ShowWindow(mdi_child2, SW_MAXIMIZE);
3727     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3728     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3729     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3730     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3731
3732     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3733     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3734     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3735     flush_sequence();
3736
3737     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3738     flush_sequence();
3739
3740     /* end of test for maximized MDI children */
3741     SetFocus(0);
3742     flush_sequence();
3743     trace("creating maximized visible MDI child window 1(Switch test)\n");
3744     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3745                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3746                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3747                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3748     assert(mdi_child);
3749     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3750     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3751
3752     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3753     ok(GetFocus() == mdi_child || /* win2k */
3754        GetFocus() == 0, /* win9x */
3755        "wrong focus window %p(Switch test)\n", GetFocus());
3756
3757     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3758     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3759     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3760     flush_sequence();
3761
3762     trace("creating maximized visible MDI child window 2(Switch test)\n");
3763     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3764                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3765                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3766                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3767     assert(mdi_child2);
3768     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3769
3770     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3771     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3772
3773     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3774     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3775
3776     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3777     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3778     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3779     flush_sequence();
3780
3781     trace("Switch child window.\n");
3782     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3783     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3784     trace("end of test for switch maximized MDI children\n");
3785     flush_sequence();
3786
3787     /* Prepare for switching test of not maximized MDI children  */
3788     ShowWindow( mdi_child, SW_NORMAL );
3789     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3790     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3791     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3792     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3793     flush_sequence();
3794
3795     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3796     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3797     trace("end of test for switch not maximized MDI children\n");
3798     flush_sequence();
3799
3800     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3801     flush_sequence();
3802
3803     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3804     flush_sequence();
3805
3806     SetFocus(0);
3807     flush_sequence();
3808     /* end of tests for switch maximized/not maximized MDI children */
3809
3810     mdi_cs.szClass = "MDI_child_Class";
3811     mdi_cs.szTitle = "MDI child";
3812     mdi_cs.hOwner = GetModuleHandleA(0);
3813     mdi_cs.x = 0;
3814     mdi_cs.y = 0;
3815     mdi_cs.cx = CW_USEDEFAULT;
3816     mdi_cs.cy = CW_USEDEFAULT;
3817     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3818     mdi_cs.lParam = 0;
3819     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3820     ok(mdi_child != 0, "MDI child creation failed\n");
3821     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3822
3823     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3824
3825     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3826     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3827
3828     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3829     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3830     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3831
3832     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3833     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3834     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3835     flush_sequence();
3836
3837     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3838     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3839
3840     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3841     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3842     ok(!active_child, "wrong active MDI child %p\n", active_child);
3843
3844     SetFocus(0);
3845     flush_sequence();
3846
3847     DestroyWindow(mdi_client);
3848     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3849
3850     /* test maximization of MDI child with invisible parent */
3851     client_cs.hWindowMenu = 0;
3852     mdi_client = CreateWindow("MDI_client_class",
3853                                  NULL,
3854                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3855                                  0, 0, 660, 430,
3856                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3857     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3858
3859     ShowWindow(mdi_client, SW_HIDE);
3860     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3861
3862     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3863                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3864                                 0, 0, 650, 440,
3865                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3866     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3867
3868     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3869     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3870     zoomed = IsZoomed(mdi_child);
3871     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3872     
3873     ShowWindow(mdi_client, SW_SHOW);
3874     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3875
3876     DestroyWindow(mdi_child);
3877     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3878
3879     /* end of test for maximization of MDI child with invisible parent */
3880
3881     DestroyWindow(mdi_client);
3882     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3883
3884     DestroyWindow(mdi_frame);
3885     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3886 }
3887 /************************* End of MDI test **********************************/
3888
3889 static void test_WM_SETREDRAW(HWND hwnd)
3890 {
3891     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3892
3893     flush_events();
3894     flush_sequence();
3895
3896     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3897     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3898
3899     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3900     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3901
3902     flush_sequence();
3903     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3904     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3905
3906     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3907     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3908
3909     /* restore original WS_VISIBLE state */
3910     SetWindowLongA(hwnd, GWL_STYLE, style);
3911
3912     flush_events();
3913     flush_sequence();
3914 }
3915
3916 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3917 {
3918     struct recvd_message msg;
3919
3920     if (ignore_message( message )) return 0;
3921
3922     switch (message)
3923     {
3924         /* ignore */
3925         case WM_MOUSEMOVE:
3926         case WM_NCMOUSEMOVE:
3927         case WM_NCMOUSELEAVE:
3928         case WM_SETCURSOR:
3929             return 0;
3930         case WM_NCHITTEST:
3931             return HTCLIENT;
3932     }
3933
3934     msg.hwnd = hwnd;
3935     msg.message = message;
3936     msg.flags = sent|wparam|lparam;
3937     msg.wParam = wParam;
3938     msg.lParam = lParam;
3939     msg.descr = "dialog";
3940     add_message(&msg);
3941
3942     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3943     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3944     return 0;
3945 }
3946
3947 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3948 {
3949     DWORD style, exstyle;
3950     INT xmin, xmax;
3951     BOOL ret;
3952
3953     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3954     style = GetWindowLongA(hwnd, GWL_STYLE);
3955     /* do not be confused by WS_DLGFRAME set */
3956     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3957
3958     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3959     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3960
3961     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3962     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3963     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3964         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3965     else
3966         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3967
3968     style = GetWindowLongA(hwnd, GWL_STYLE);
3969     if (set) ok(style & set, "style %08x should be set\n", set);
3970     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3971
3972     /* a subsequent call should do nothing */
3973     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3974     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3975     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3976
3977     xmin = 0xdeadbeef;
3978     xmax = 0xdeadbeef;
3979     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3980     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3981     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3982     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3983     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3984 }
3985
3986 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3987 {
3988     DWORD style, exstyle;
3989     SCROLLINFO si;
3990     BOOL ret;
3991
3992     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3993     style = GetWindowLongA(hwnd, GWL_STYLE);
3994     /* do not be confused by WS_DLGFRAME set */
3995     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3996
3997     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3998     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3999
4000     si.cbSize = sizeof(si);
4001     si.fMask = SIF_RANGE;
4002     si.nMin = min;
4003     si.nMax = max;
4004     SetScrollInfo(hwnd, ctl, &si, TRUE);
4005     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4006         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4007     else
4008         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4009
4010     style = GetWindowLongA(hwnd, GWL_STYLE);
4011     if (set) ok(style & set, "style %08x should be set\n", set);
4012     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4013
4014     /* a subsequent call should do nothing */
4015     SetScrollInfo(hwnd, ctl, &si, TRUE);
4016     if (style & WS_HSCROLL)
4017         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4018     else if (style & WS_VSCROLL)
4019         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4020     else
4021         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4022
4023     si.fMask = SIF_PAGE;
4024     si.nPage = 5;
4025     SetScrollInfo(hwnd, ctl, &si, FALSE);
4026     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4027
4028     si.fMask = SIF_POS;
4029     si.nPos = max - 1;
4030     SetScrollInfo(hwnd, ctl, &si, FALSE);
4031     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4032
4033     si.fMask = SIF_RANGE;
4034     si.nMin = 0xdeadbeef;
4035     si.nMax = 0xdeadbeef;
4036     ret = GetScrollInfo(hwnd, ctl, &si);
4037     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4038     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4039     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4040     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4041 }
4042
4043 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4044 static void test_scroll_messages(HWND hwnd)
4045 {
4046     SCROLLINFO si;
4047     INT min, max;
4048     BOOL ret;
4049
4050     flush_events();
4051     flush_sequence();
4052
4053     min = 0xdeadbeef;
4054     max = 0xdeadbeef;
4055     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4056     ok( ret, "GetScrollRange error %d\n", GetLastError());
4057     if (sequence->message != WmGetScrollRangeSeq[0].message)
4058         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4059     /* values of min and max are undefined */
4060     flush_sequence();
4061
4062     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4063     ok( ret, "SetScrollRange error %d\n", GetLastError());
4064     if (sequence->message != WmSetScrollRangeSeq[0].message)
4065         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4066     flush_sequence();
4067
4068     min = 0xdeadbeef;
4069     max = 0xdeadbeef;
4070     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4071     ok( ret, "GetScrollRange error %d\n", GetLastError());
4072     if (sequence->message != WmGetScrollRangeSeq[0].message)
4073         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4074     /* values of min and max are undefined */
4075     flush_sequence();
4076
4077     si.cbSize = sizeof(si);
4078     si.fMask = SIF_RANGE;
4079     si.nMin = 20;
4080     si.nMax = 160;
4081     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4082     if (sequence->message != WmSetScrollRangeSeq[0].message)
4083         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4084     flush_sequence();
4085
4086     si.fMask = SIF_PAGE;
4087     si.nPage = 10;
4088     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4089     if (sequence->message != WmSetScrollRangeSeq[0].message)
4090         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4091     flush_sequence();
4092
4093     si.fMask = SIF_POS;
4094     si.nPos = 20;
4095     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4096     if (sequence->message != WmSetScrollRangeSeq[0].message)
4097         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4098     flush_sequence();
4099
4100     si.fMask = SIF_RANGE;
4101     si.nMin = 0xdeadbeef;
4102     si.nMax = 0xdeadbeef;
4103     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4104     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4105     if (sequence->message != WmGetScrollInfoSeq[0].message)
4106         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4107     /* values of min and max are undefined */
4108     flush_sequence();
4109
4110     /* set WS_HSCROLL */
4111     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4112     /* clear WS_HSCROLL */
4113     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4114
4115     /* set WS_HSCROLL */
4116     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4117     /* clear WS_HSCROLL */
4118     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4119
4120     /* set WS_VSCROLL */
4121     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4122     /* clear WS_VSCROLL */
4123     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4124
4125     /* set WS_VSCROLL */
4126     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4127     /* clear WS_VSCROLL */
4128     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4129 }
4130
4131 static void test_showwindow(void)
4132 {
4133     HWND hwnd, hchild;
4134     RECT rc;
4135
4136     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4137                            100, 100, 200, 200, 0, 0, 0, NULL);
4138     ok (hwnd != 0, "Failed to create overlapped window\n");
4139     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4140                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4141     ok (hchild != 0, "Failed to create child\n");
4142     flush_sequence();
4143
4144     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4145     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4146     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4147     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4148
4149     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4150     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4151     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4152     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4153     /* back to invisible */
4154     ShowWindow(hchild, SW_HIDE);
4155     ShowWindow(hwnd, SW_HIDE);
4156     flush_sequence();
4157     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4158     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4159     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4160     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4161     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4162     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4163     flush_sequence();
4164     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4165     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4166     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4167     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4168     ShowWindow( hwnd, SW_SHOW);
4169     flush_sequence();
4170     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4171     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4172     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4173
4174     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4175     ShowWindow( hchild, SW_HIDE);
4176     flush_sequence();
4177     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4178     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4179     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4180
4181     SetCapture(hchild);
4182     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4183     DestroyWindow(hchild);
4184     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4185
4186     DestroyWindow(hwnd);
4187     flush_sequence();
4188
4189     /* Popup windows */
4190     /* Test 1:
4191      * 1. Create invisible maximized popup window.
4192      * 2. Move and resize it.
4193      * 3. Show it maximized.
4194      */
4195     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4196     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4197                            100, 100, 200, 200, 0, 0, 0, NULL);
4198     ok (hwnd != 0, "Failed to create popup window\n");
4199     ok(IsZoomed(hwnd), "window should be maximized\n");
4200     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4201
4202     GetWindowRect(hwnd, &rc);
4203     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4204         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4205         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4206         rc.left, rc.top, rc.right, rc.bottom);
4207     /* Reset window's size & position */
4208     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4209     ok(IsZoomed(hwnd), "window should be maximized\n");
4210     flush_sequence();
4211
4212     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4213     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4214     ok(IsZoomed(hwnd), "window should be maximized\n");
4215     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4216
4217     GetWindowRect(hwnd, &rc);
4218     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4219         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4220         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4221         rc.left, rc.top, rc.right, rc.bottom);
4222     DestroyWindow(hwnd);
4223     flush_sequence();
4224
4225     /* Test 2:
4226      * 1. Create invisible maximized popup window.
4227      * 2. Show it maximized.
4228      */
4229     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4230     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4231                            100, 100, 200, 200, 0, 0, 0, NULL);
4232     ok (hwnd != 0, "Failed to create popup window\n");
4233     ok(IsZoomed(hwnd), "window should be maximized\n");
4234     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4235
4236     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4237     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4238     ok(IsZoomed(hwnd), "window should be maximized\n");
4239     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4240     DestroyWindow(hwnd);
4241     flush_sequence();
4242
4243     /* Test 3:
4244      * 1. Create visible maximized popup window.
4245      */
4246     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4247     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4248                            100, 100, 200, 200, 0, 0, 0, NULL);
4249     ok (hwnd != 0, "Failed to create popup window\n");
4250     ok(IsZoomed(hwnd), "window should be maximized\n");
4251     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4252     DestroyWindow(hwnd);
4253     flush_sequence();
4254
4255     /* Test 4:
4256      * 1. Create visible popup window.
4257      * 2. Maximize it.
4258      */
4259     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4260     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4261                            100, 100, 200, 200, 0, 0, 0, NULL);
4262     ok (hwnd != 0, "Failed to create popup window\n");
4263     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4264     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4265
4266     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4267     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4268     ok(IsZoomed(hwnd), "window should be maximized\n");
4269     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4270     DestroyWindow(hwnd);
4271     flush_sequence();
4272 }
4273
4274 static void test_sys_menu(void)
4275 {
4276     HWND hwnd;
4277     HMENU hmenu;
4278     UINT state;
4279
4280     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4281                            100, 100, 200, 200, 0, 0, 0, NULL);
4282     ok (hwnd != 0, "Failed to create overlapped window\n");
4283
4284     flush_sequence();
4285
4286     /* test existing window without CS_NOCLOSE style */
4287     hmenu = GetSystemMenu(hwnd, FALSE);
4288     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4289
4290     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4291     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4292     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4293
4294     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4295     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4296
4297     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4298     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4299     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4300
4301     EnableMenuItem(hmenu, SC_CLOSE, 0);
4302     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4303
4304     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4305     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4306     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4307
4308     /* test whether removing WS_SYSMENU destroys a system menu */
4309     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4310     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4311     flush_sequence();
4312     hmenu = GetSystemMenu(hwnd, FALSE);
4313     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4314
4315     DestroyWindow(hwnd);
4316
4317     /* test new window with CS_NOCLOSE style */
4318     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4319                            100, 100, 200, 200, 0, 0, 0, NULL);
4320     ok (hwnd != 0, "Failed to create overlapped window\n");
4321
4322     hmenu = GetSystemMenu(hwnd, FALSE);
4323     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4324
4325     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4326     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4327
4328     DestroyWindow(hwnd);
4329
4330     /* test new window without WS_SYSMENU style */
4331     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4332                            100, 100, 200, 200, 0, 0, 0, NULL);
4333     ok(hwnd != 0, "Failed to create overlapped window\n");
4334
4335     hmenu = GetSystemMenu(hwnd, FALSE);
4336     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4337
4338     DestroyWindow(hwnd);
4339 }
4340
4341 /* For shown WS_OVERLAPPEDWINDOW */
4342 static const struct message WmSetIcon_1[] = {
4343     { WM_SETICON, sent },
4344     { 0x00AE, sent|defwinproc|optional }, /* XP */
4345     { WM_GETTEXT, sent|defwinproc|optional },
4346     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4347     { 0 }
4348 };
4349
4350 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4351 static const struct message WmSetIcon_2[] = {
4352     { WM_SETICON, sent },
4353     { 0 }
4354 };
4355
4356 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4357 static const struct message WmInitEndSession[] = {
4358     { 0x003B, sent },
4359     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4360     { 0 }
4361 };
4362
4363 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4364 static const struct message WmInitEndSession_2[] = {
4365     { 0x003B, sent },
4366     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4367     { 0 }
4368 };
4369
4370 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4371 static const struct message WmInitEndSession_3[] = {
4372     { 0x003B, sent },
4373     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4374     { 0 }
4375 };
4376
4377 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4378 static const struct message WmInitEndSession_4[] = {
4379     { 0x003B, sent },
4380     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4381     { 0 }
4382 };
4383
4384 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4385 static const struct message WmInitEndSession_5[] = {
4386     { 0x003B, sent },
4387     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4388     { 0 }
4389 };
4390
4391 static const struct message WmOptionalPaint[] = {
4392     { WM_PAINT, sent|optional },
4393     { WM_NCPAINT, sent|beginpaint|optional },
4394     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4395     { WM_ERASEBKGND, sent|beginpaint|optional },
4396     { 0 }
4397 };
4398
4399 static const struct message WmZOrder[] = {
4400     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4401     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4402     { HCBT_ACTIVATE, hook },
4403     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4404     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4405     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4406     { WM_GETTEXT, sent|optional },
4407     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4408     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4409     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4410     { WM_GETTEXT, sent|defwinproc|optional },
4411     { WM_GETTEXT, sent|defwinproc|optional },
4412     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4413     { HCBT_SETFOCUS, hook },
4414     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4415     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4416     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4417     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4418     { WM_GETTEXT, sent|optional },
4419     { WM_NCCALCSIZE, sent|optional },
4420     { 0 }
4421 };
4422
4423 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4424 {
4425     DWORD ret;
4426     MSG msg;
4427
4428     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4429     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4430
4431     PostMessageA(hwnd, WM_USER, 0, 0);
4432
4433     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4434     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4435
4436     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4437     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4438
4439     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4440     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4441
4442     PostMessageA(hwnd, WM_USER, 0, 0);
4443
4444     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4445     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4446
4447     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4448     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4449
4450     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
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     /* new incoming message causes it to become signaled again */
4457     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4458     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4459
4460     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4461     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4462     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4463     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4464 }
4465
4466 /* test if we receive the right sequence of messages */
4467 static void test_messages(void)
4468 {
4469     HWND hwnd, hparent, hchild;
4470     HWND hchild2, hbutton;
4471     HMENU hmenu;
4472     MSG msg;
4473     LRESULT res;
4474
4475     flush_sequence();
4476
4477     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4478                            100, 100, 200, 200, 0, 0, 0, NULL);
4479     ok (hwnd != 0, "Failed to create overlapped window\n");
4480     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4481
4482     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4483     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4484     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4485
4486     /* test WM_SETREDRAW on a not visible top level window */
4487     test_WM_SETREDRAW(hwnd);
4488
4489     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4490     flush_events();
4491     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4492     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4493
4494     ok(GetActiveWindow() == hwnd, "window should be active\n");
4495     ok(GetFocus() == hwnd, "window should have input focus\n");
4496     ShowWindow(hwnd, SW_HIDE);
4497     flush_events();
4498     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4499
4500     ShowWindow(hwnd, SW_SHOW);
4501     flush_events();
4502     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4503
4504     ShowWindow(hwnd, SW_HIDE);
4505     flush_events();
4506     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4507
4508     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4509     flush_events();
4510     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4511     flush_sequence();
4512
4513     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4514     {
4515         ShowWindow(hwnd, SW_RESTORE);
4516         flush_events();
4517         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4518         flush_sequence();
4519     }
4520
4521     ShowWindow(hwnd, SW_MINIMIZE);
4522     flush_events();
4523     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4524     flush_sequence();
4525
4526     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4527     {
4528         ShowWindow(hwnd, SW_RESTORE);
4529         flush_events();
4530         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4531         flush_sequence();
4532     }
4533
4534     ShowWindow(hwnd, SW_SHOW);
4535     flush_events();
4536     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4537
4538     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4539     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4540     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4541     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4542
4543     /* test WM_SETREDRAW on a visible top level window */
4544     ShowWindow(hwnd, SW_SHOW);
4545     flush_events();
4546     test_WM_SETREDRAW(hwnd);
4547
4548     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4549     test_scroll_messages(hwnd);
4550
4551     /* test resizing and moving */
4552     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4553     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4554     flush_events();
4555     flush_sequence();
4556     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4557     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4558     flush_events();
4559     flush_sequence();
4560     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4561     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4562     flush_events();
4563     flush_sequence();
4564
4565     /* popups don't get WM_GETMINMAXINFO */
4566     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4567     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4568     flush_sequence();
4569     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4570     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4571
4572     DestroyWindow(hwnd);
4573     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4574
4575     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4576                               100, 100, 200, 200, 0, 0, 0, NULL);
4577     ok (hparent != 0, "Failed to create parent window\n");
4578     flush_sequence();
4579
4580     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4581                              0, 0, 10, 10, hparent, 0, 0, NULL);
4582     ok (hchild != 0, "Failed to create child window\n");
4583     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4584     DestroyWindow(hchild);
4585     flush_sequence();
4586
4587     /* visible child window with a caption */
4588     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4589                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4590                              0, 0, 10, 10, hparent, 0, 0, NULL);
4591     ok (hchild != 0, "Failed to create child window\n");
4592     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4593
4594     trace("testing scroll APIs on a visible child window %p\n", hchild);
4595     test_scroll_messages(hchild);
4596
4597     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4598     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4599
4600     DestroyWindow(hchild);
4601     flush_sequence();
4602
4603     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4604                              0, 0, 10, 10, hparent, 0, 0, NULL);
4605     ok (hchild != 0, "Failed to create child window\n");
4606     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4607     
4608     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4609                                100, 100, 50, 50, hparent, 0, 0, NULL);
4610     ok (hchild2 != 0, "Failed to create child2 window\n");
4611     flush_sequence();
4612
4613     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4614                               0, 100, 50, 50, hchild, 0, 0, NULL);
4615     ok (hbutton != 0, "Failed to create button window\n");
4616
4617     /* test WM_SETREDRAW on a not visible child window */
4618     test_WM_SETREDRAW(hchild);
4619
4620     ShowWindow(hchild, SW_SHOW);
4621     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4622
4623     /* check parent messages too */
4624     log_all_parent_messages++;
4625     ShowWindow(hchild, SW_HIDE);
4626     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4627     log_all_parent_messages--;
4628
4629     ShowWindow(hchild, SW_SHOW);
4630     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4631
4632     ShowWindow(hchild, SW_HIDE);
4633     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4634
4635     ShowWindow(hchild, SW_SHOW);
4636     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4637
4638     /* test WM_SETREDRAW on a visible child window */
4639     test_WM_SETREDRAW(hchild);
4640
4641     log_all_parent_messages++;
4642     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4643     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4644     log_all_parent_messages--;
4645
4646     ShowWindow(hchild, SW_HIDE);
4647     flush_sequence();
4648     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4649     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4650
4651     ShowWindow(hchild, SW_HIDE);
4652     flush_sequence();
4653     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4654     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4655
4656     /* DestroyWindow sequence below expects that a child has focus */
4657     SetFocus(hchild);
4658     flush_sequence();
4659
4660     DestroyWindow(hchild);
4661     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4662     DestroyWindow(hchild2);
4663     DestroyWindow(hbutton);
4664
4665     flush_sequence();
4666     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4667                              0, 0, 100, 100, hparent, 0, 0, NULL);
4668     ok (hchild != 0, "Failed to create child popup window\n");
4669     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4670     DestroyWindow(hchild);
4671
4672     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4673     flush_sequence();
4674     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4675                              0, 0, 100, 100, hparent, 0, 0, NULL);
4676     ok (hchild != 0, "Failed to create popup window\n");
4677     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4678     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4679     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4680     flush_sequence();
4681     ShowWindow(hchild, SW_SHOW);
4682     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4683     flush_sequence();
4684     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4685     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4686     flush_sequence();
4687     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4688     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4689     DestroyWindow(hchild);
4690
4691     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4692      * changes nothing in message sequences.
4693      */
4694     flush_sequence();
4695     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4696                              0, 0, 100, 100, hparent, 0, 0, NULL);
4697     ok (hchild != 0, "Failed to create popup window\n");
4698     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4699     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4700     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4701     flush_sequence();
4702     ShowWindow(hchild, SW_SHOW);
4703     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4704     flush_sequence();
4705     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4706     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4707     DestroyWindow(hchild);
4708
4709     flush_sequence();
4710     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4711                            0, 0, 100, 100, hparent, 0, 0, NULL);
4712     ok(hwnd != 0, "Failed to create custom dialog window\n");
4713     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4714
4715     /*
4716     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4717     test_scroll_messages(hwnd);
4718     */
4719
4720     flush_sequence();
4721
4722     test_def_id = 1;
4723     SendMessage(hwnd, WM_NULL, 0, 0);
4724
4725     flush_sequence();
4726     after_end_dialog = 1;
4727     EndDialog( hwnd, 0 );
4728     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4729
4730     DestroyWindow(hwnd);
4731     after_end_dialog = 0;
4732     test_def_id = 0;
4733
4734     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4735                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4736     ok(hwnd != 0, "Failed to create custom dialog window\n");
4737     flush_sequence();
4738     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4739     ShowWindow(hwnd, SW_SHOW);
4740     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4741     DestroyWindow(hwnd);
4742
4743     flush_sequence();
4744     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4745     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4746
4747     DestroyWindow(hparent);
4748     flush_sequence();
4749
4750     /* Message sequence for SetMenu */
4751     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4752     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4753
4754     hmenu = CreateMenu();
4755     ok (hmenu != 0, "Failed to create menu\n");
4756     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4757     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4758                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4759     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4760     ok (SetMenu(hwnd, 0), "SetMenu\n");
4761     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4762     ok (SetMenu(hwnd, 0), "SetMenu\n");
4763     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4764     ShowWindow(hwnd, SW_SHOW);
4765     UpdateWindow( hwnd );
4766     flush_events();
4767     flush_sequence();
4768     ok (SetMenu(hwnd, 0), "SetMenu\n");
4769     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4770     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4771     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4772
4773     UpdateWindow( hwnd );
4774     flush_events();
4775     flush_sequence();
4776     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4777     flush_events();
4778     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4779
4780     DestroyWindow(hwnd);
4781     flush_sequence();
4782
4783     /* Message sequence for EnableWindow */
4784     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4785                               100, 100, 200, 200, 0, 0, 0, NULL);
4786     ok (hparent != 0, "Failed to create parent window\n");
4787     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4788                              0, 0, 10, 10, hparent, 0, 0, NULL);
4789     ok (hchild != 0, "Failed to create child window\n");
4790
4791     SetFocus(hchild);
4792     flush_events();
4793     flush_sequence();
4794
4795     EnableWindow(hparent, FALSE);
4796     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4797
4798     EnableWindow(hparent, TRUE);
4799     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4800
4801     flush_events();
4802     flush_sequence();
4803
4804     test_MsgWaitForMultipleObjects(hparent);
4805
4806     /* the following test causes an exception in user.exe under win9x */
4807     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4808     {
4809         DestroyWindow(hparent);
4810         flush_sequence();
4811         return;
4812     }
4813     PostMessageW( hparent, WM_USER+1, 0, 0 );
4814     /* PeekMessage(NULL) fails, but still removes the message */
4815     SetLastError(0xdeadbeef);
4816     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4817     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4818         GetLastError() == 0xdeadbeef, /* NT4 */
4819         "last error is %d\n", GetLastError() );
4820     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4821     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4822
4823     DestroyWindow(hchild);
4824     DestroyWindow(hparent);
4825     flush_sequence();
4826
4827     /* Message sequences for WM_SETICON */
4828     trace("testing WM_SETICON\n");
4829     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4830                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4831                            NULL, NULL, 0);
4832     ShowWindow(hwnd, SW_SHOW);
4833     UpdateWindow(hwnd);
4834     flush_events();
4835     flush_sequence();
4836     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4837     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4838
4839     ShowWindow(hwnd, SW_HIDE);
4840     flush_events();
4841     flush_sequence();
4842     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4843     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4844     DestroyWindow(hwnd);
4845     flush_sequence();
4846
4847     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4848                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4849                            NULL, NULL, 0);
4850     ShowWindow(hwnd, SW_SHOW);
4851     UpdateWindow(hwnd);
4852     flush_events();
4853     flush_sequence();
4854     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4855     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4856
4857     ShowWindow(hwnd, SW_HIDE);
4858     flush_events();
4859     flush_sequence();
4860     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4861     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4862
4863     flush_sequence();
4864     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4865     if (!res)
4866     {
4867         todo_wine win_skip( "Message 0x3b not supported\n" );
4868         goto done;
4869     }
4870     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4871     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4872     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4873     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4874     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4875     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4876     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4877     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4878
4879     flush_sequence();
4880     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4881     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4882     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4883     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4884     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4885     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4886
4887     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4888     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4889     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4890
4891     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4892     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4893     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4894
4895 done:
4896     DestroyWindow(hwnd);
4897     flush_sequence();
4898 }
4899
4900 static void test_setwindowpos(void)
4901 {
4902     HWND hwnd;
4903     RECT rc;
4904     LRESULT res;
4905     const INT winX = 100;
4906     const INT winY = 100;
4907     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4908
4909     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4910                            0, 0, winX, winY, 0,
4911                            NULL, NULL, 0);
4912
4913     GetWindowRect(hwnd, &rc);
4914     expect(sysX, rc.right);
4915     expect(winY, rc.bottom);
4916
4917     flush_events();
4918     flush_sequence();
4919     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4920     ok_sequence(WmZOrder, "Z-Order", TRUE);
4921     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4922
4923     GetWindowRect(hwnd, &rc);
4924     expect(sysX, rc.right);
4925     expect(winY, rc.bottom);
4926     DestroyWindow(hwnd);
4927 }
4928
4929 static void invisible_parent_tests(void)
4930 {
4931     HWND hparent, hchild;
4932
4933     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4934                               100, 100, 200, 200, 0, 0, 0, NULL);
4935     ok (hparent != 0, "Failed to create parent window\n");
4936     flush_sequence();
4937
4938     /* test showing child with hidden parent */
4939
4940     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4941                              0, 0, 10, 10, hparent, 0, 0, NULL);
4942     ok (hchild != 0, "Failed to create child window\n");
4943     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4944
4945     ShowWindow( hchild, SW_MINIMIZE );
4946     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4947     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4948     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4949
4950     /* repeat */
4951     flush_events();
4952     flush_sequence();
4953     ShowWindow( hchild, SW_MINIMIZE );
4954     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4955
4956     DestroyWindow(hchild);
4957     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4958                              0, 0, 10, 10, hparent, 0, 0, NULL);
4959     flush_sequence();
4960
4961     ShowWindow( hchild, SW_MAXIMIZE );
4962     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4963     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4964     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4965
4966     /* repeat */
4967     flush_events();
4968     flush_sequence();
4969     ShowWindow( hchild, SW_MAXIMIZE );
4970     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4971
4972     DestroyWindow(hchild);
4973     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4974                              0, 0, 10, 10, hparent, 0, 0, NULL);
4975     flush_sequence();
4976
4977     ShowWindow( hchild, SW_RESTORE );
4978     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4979     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4980     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4981
4982     DestroyWindow(hchild);
4983     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4984                              0, 0, 10, 10, hparent, 0, 0, NULL);
4985     flush_sequence();
4986
4987     ShowWindow( hchild, SW_SHOWMINIMIZED );
4988     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4989     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4990     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4991
4992     /* repeat */
4993     flush_events();
4994     flush_sequence();
4995     ShowWindow( hchild, SW_SHOWMINIMIZED );
4996     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4997
4998     DestroyWindow(hchild);
4999     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5000                              0, 0, 10, 10, hparent, 0, 0, NULL);
5001     flush_sequence();
5002
5003     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5004     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5005     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5006     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5007     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5008
5009     DestroyWindow(hchild);
5010     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5011                              0, 0, 10, 10, hparent, 0, 0, NULL);
5012     flush_sequence();
5013
5014     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5015     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5016     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5017     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5018
5019     /* repeat */
5020     flush_events();
5021     flush_sequence();
5022     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5023     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5024
5025     DestroyWindow(hchild);
5026     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5027                              0, 0, 10, 10, hparent, 0, 0, NULL);
5028     flush_sequence();
5029
5030     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5031     ShowWindow( hchild, SW_FORCEMINIMIZE );
5032     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5033 todo_wine {
5034     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5035 }
5036     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5037
5038     DestroyWindow(hchild);
5039     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5040                              0, 0, 10, 10, hparent, 0, 0, NULL);
5041     flush_sequence();
5042
5043     ShowWindow( hchild, SW_SHOWNA );
5044     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5045     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5046     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5047
5048     /* repeat */
5049     flush_events();
5050     flush_sequence();
5051     ShowWindow( hchild, SW_SHOWNA );
5052     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5053
5054     DestroyWindow(hchild);
5055     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5056                              0, 0, 10, 10, hparent, 0, 0, NULL);
5057     flush_sequence();
5058
5059     ShowWindow( hchild, SW_SHOW );
5060     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5061     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5062     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5063
5064     /* repeat */
5065     flush_events();
5066     flush_sequence();
5067     ShowWindow( hchild, SW_SHOW );
5068     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5069
5070     ShowWindow( hchild, SW_HIDE );
5071     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5072     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5073     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5074
5075     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5076     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5077     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5078     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5079
5080     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5081     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5082     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5083     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5084
5085     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5086     flush_sequence();
5087     DestroyWindow(hchild);
5088     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5089
5090     DestroyWindow(hparent);
5091     flush_sequence();
5092 }
5093
5094 /****************** button message test *************************/
5095 #define ID_BUTTON 0x000e
5096
5097 static const struct message WmSetFocusButtonSeq[] =
5098 {
5099     { HCBT_SETFOCUS, hook },
5100     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5101     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5102     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5103     { WM_SETFOCUS, sent|wparam, 0 },
5104     { WM_CTLCOLORBTN, sent|parent },
5105     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5106     { WM_APP, sent|wparam|lparam, 0, 0 },
5107     { 0 }
5108 };
5109 static const struct message WmKillFocusButtonSeq[] =
5110 {
5111     { HCBT_SETFOCUS, hook },
5112     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5113     { WM_KILLFOCUS, sent|wparam, 0 },
5114     { WM_CTLCOLORBTN, sent|parent },
5115     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5116     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5117     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5118     { WM_APP, sent|wparam|lparam, 0, 0 },
5119     { WM_PAINT, sent },
5120     { WM_CTLCOLORBTN, sent|parent },
5121     { 0 }
5122 };
5123 static const struct message WmSetFocusStaticSeq[] =
5124 {
5125     { HCBT_SETFOCUS, hook },
5126     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5127     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5128     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5129     { WM_SETFOCUS, sent|wparam, 0 },
5130     { WM_CTLCOLORSTATIC, sent|parent },
5131     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5132     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5133     { WM_APP, sent|wparam|lparam, 0, 0 },
5134     { 0 }
5135 };
5136 static const struct message WmKillFocusStaticSeq[] =
5137 {
5138     { HCBT_SETFOCUS, hook },
5139     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5140     { WM_KILLFOCUS, sent|wparam, 0 },
5141     { WM_CTLCOLORSTATIC, sent|parent },
5142     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5143     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5144     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5145     { WM_APP, sent|wparam|lparam, 0, 0 },
5146     { WM_PAINT, sent },
5147     { WM_CTLCOLORSTATIC, sent|parent },
5148     { 0 }
5149 };
5150 static const struct message WmSetFocusOwnerdrawSeq[] =
5151 {
5152     { HCBT_SETFOCUS, hook },
5153     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5154     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5155     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5156     { WM_SETFOCUS, sent|wparam, 0 },
5157     { WM_CTLCOLORBTN, sent|parent },
5158     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5159     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5160     { WM_APP, sent|wparam|lparam, 0, 0 },
5161     { 0 }
5162 };
5163 static const struct message WmKillFocusOwnerdrawSeq[] =
5164 {
5165     { HCBT_SETFOCUS, hook },
5166     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5167     { WM_KILLFOCUS, sent|wparam, 0 },
5168     { WM_CTLCOLORBTN, sent|parent },
5169     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5170     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5171     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5172     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5173     { WM_APP, sent|wparam|lparam, 0, 0 },
5174     { WM_PAINT, sent },
5175     { WM_CTLCOLORBTN, sent|parent },
5176     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5177     { 0 }
5178 };
5179 static const struct message WmLButtonDownSeq[] =
5180 {
5181     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5182     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5183     { HCBT_SETFOCUS, hook },
5184     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5185     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5186     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5187     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5188     { WM_CTLCOLORBTN, sent|defwinproc },
5189     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5190     { WM_CTLCOLORBTN, sent|defwinproc },
5191     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5192     { 0 }
5193 };
5194 static const struct message WmLButtonUpSeq[] =
5195 {
5196     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5197     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5198     { WM_CTLCOLORBTN, sent|defwinproc },
5199     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5200     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5201     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5202     { 0 }
5203 };
5204 static const struct message WmSetFontButtonSeq[] =
5205 {
5206     { WM_SETFONT, sent },
5207     { WM_PAINT, sent },
5208     { WM_ERASEBKGND, sent|defwinproc|optional },
5209     { WM_CTLCOLORBTN, sent|defwinproc },
5210     { 0 }
5211 };
5212
5213 static WNDPROC old_button_proc;
5214
5215 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5216 {
5217     static long defwndproc_counter = 0;
5218     LRESULT ret;
5219     struct recvd_message msg;
5220
5221     if (ignore_message( message )) return 0;
5222
5223     switch (message)
5224     {
5225     case WM_SYNCPAINT:
5226         break;
5227     case BM_SETSTATE:
5228         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5229         /* fall through */
5230     default:
5231         msg.hwnd = hwnd;
5232         msg.message = message;
5233         msg.flags = sent|wparam|lparam;
5234         if (defwndproc_counter) msg.flags |= defwinproc;
5235         msg.wParam = wParam;
5236         msg.lParam = lParam;
5237         msg.descr = "button";
5238         add_message(&msg);
5239     }
5240
5241     defwndproc_counter++;
5242     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5243     defwndproc_counter--;
5244
5245     return ret;
5246 }
5247
5248 static void subclass_button(void)
5249 {
5250     WNDCLASSA cls;
5251
5252     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5253
5254     old_button_proc = cls.lpfnWndProc;
5255
5256     cls.hInstance = GetModuleHandle(0);
5257     cls.lpfnWndProc = button_hook_proc;
5258     cls.lpszClassName = "my_button_class";
5259     UnregisterClass(cls.lpszClassName, cls.hInstance);
5260     if (!RegisterClassA(&cls)) assert(0);
5261 }
5262
5263 static void test_button_messages(void)
5264 {
5265     static const struct
5266     {
5267         DWORD style;
5268         DWORD dlg_code;
5269         const struct message *setfocus;
5270         const struct message *killfocus;
5271     } button[] = {
5272         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5273           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5274         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5275           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5276         { BS_CHECKBOX, DLGC_BUTTON,
5277           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5278         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5279           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5280         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5281           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5282         { BS_3STATE, DLGC_BUTTON,
5283           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5284         { BS_AUTO3STATE, DLGC_BUTTON,
5285           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5286         { BS_GROUPBOX, DLGC_STATIC,
5287           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5288         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5289           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5290         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5291           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5292         { BS_OWNERDRAW, DLGC_BUTTON,
5293           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq }
5294     };
5295     unsigned int i;
5296     HWND hwnd, parent;
5297     DWORD dlg_code;
5298     HFONT zfont;
5299
5300     /* selection with VK_SPACE should capture button window */
5301     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5302                            0, 0, 50, 14, 0, 0, 0, NULL);
5303     ok(hwnd != 0, "Failed to create button window\n");
5304     ReleaseCapture();
5305     SetFocus(hwnd);
5306     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5307     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5308     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5309     DestroyWindow(hwnd);
5310
5311     subclass_button();
5312
5313     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5314                              100, 100, 200, 200, 0, 0, 0, NULL);
5315     ok(parent != 0, "Failed to create parent window\n");
5316
5317     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5318     {
5319         MSG msg;
5320         DWORD style;
5321
5322         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5323                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5324         ok(hwnd != 0, "Failed to create button window\n");
5325
5326         style = GetWindowLongA(hwnd, GWL_STYLE);
5327         style &= ~(WS_CHILD | BS_NOTIFY);
5328         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5329         if (button[i].style == BS_USERBUTTON)
5330             todo_wine ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5331         else
5332         ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5333
5334         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5335         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5336
5337         ShowWindow(hwnd, SW_SHOW);
5338         UpdateWindow(hwnd);
5339         SetFocus(0);
5340         flush_events();
5341         flush_sequence();
5342
5343         log_all_parent_messages++;
5344
5345         trace("button style %08x\n", button[i].style);
5346         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5347         SetFocus(hwnd);
5348         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5349         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5350         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5351
5352         SetFocus(0);
5353         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5354         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5355         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5356
5357         log_all_parent_messages--;
5358
5359         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5360         DestroyWindow(hwnd);
5361     }
5362
5363     DestroyWindow(parent);
5364
5365     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5366                            0, 0, 50, 14, 0, 0, 0, NULL);
5367     ok(hwnd != 0, "Failed to create button window\n");
5368
5369     SetForegroundWindow(hwnd);
5370     flush_events();
5371
5372     SetActiveWindow(hwnd);
5373     SetFocus(0);
5374     flush_sequence();
5375
5376     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5377     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5378
5379     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5380     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5381
5382     flush_sequence();
5383     zfont = GetStockObject(SYSTEM_FONT);
5384     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5385     UpdateWindow(hwnd);
5386     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5387
5388     DestroyWindow(hwnd);
5389 }
5390
5391 /****************** static message test *************************/
5392 static const struct message WmSetFontStaticSeq[] =
5393 {
5394     { WM_SETFONT, sent },
5395     { WM_PAINT, sent|defwinproc|optional },
5396     { WM_ERASEBKGND, sent|defwinproc|optional },
5397     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5398     { 0 }
5399 };
5400
5401 static WNDPROC old_static_proc;
5402
5403 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5404 {
5405     static long defwndproc_counter = 0;
5406     LRESULT ret;
5407     struct recvd_message msg;
5408
5409     if (ignore_message( message )) return 0;
5410
5411     msg.hwnd = hwnd;
5412     msg.message = message;
5413     msg.flags = sent|wparam|lparam;
5414     if (defwndproc_counter) msg.flags |= defwinproc;
5415     msg.wParam = wParam;
5416     msg.lParam = lParam;
5417     msg.descr = "static";
5418     add_message(&msg);
5419
5420     defwndproc_counter++;
5421     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5422     defwndproc_counter--;
5423
5424     return ret;
5425 }
5426
5427 static void subclass_static(void)
5428 {
5429     WNDCLASSA cls;
5430
5431     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5432
5433     old_static_proc = cls.lpfnWndProc;
5434
5435     cls.hInstance = GetModuleHandle(0);
5436     cls.lpfnWndProc = static_hook_proc;
5437     cls.lpszClassName = "my_static_class";
5438     UnregisterClass(cls.lpszClassName, cls.hInstance);
5439     if (!RegisterClassA(&cls)) assert(0);
5440 }
5441
5442 static void test_static_messages(void)
5443 {
5444     /* FIXME: make as comprehensive as the button message test */
5445     static const struct
5446     {
5447         DWORD style;
5448         DWORD dlg_code;
5449         const struct message *setfont;
5450     } static_ctrl[] = {
5451         { SS_LEFT, DLGC_STATIC,
5452           WmSetFontStaticSeq }
5453     };
5454     unsigned int i;
5455     HWND hwnd;
5456     DWORD dlg_code;
5457
5458     subclass_static();
5459
5460     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5461     {
5462         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5463                                0, 0, 50, 14, 0, 0, 0, NULL);
5464         ok(hwnd != 0, "Failed to create static window\n");
5465
5466         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5467         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5468
5469         ShowWindow(hwnd, SW_SHOW);
5470         UpdateWindow(hwnd);
5471         SetFocus(0);
5472         flush_sequence();
5473
5474         trace("static style %08x\n", static_ctrl[i].style);
5475         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5476         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5477
5478         DestroyWindow(hwnd);
5479     }
5480 }
5481
5482 /****************** ComboBox message test *************************/
5483 #define ID_COMBOBOX 0x000f
5484
5485 static const struct message WmKeyDownComboSeq[] =
5486 {
5487     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5488     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5489     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5490     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5491     { WM_CTLCOLOREDIT, sent|parent },
5492     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5493     { 0 }
5494 };
5495
5496 static WNDPROC old_combobox_proc;
5497
5498 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5499 {
5500     static long defwndproc_counter = 0;
5501     LRESULT ret;
5502     struct recvd_message msg;
5503
5504     /* do not log painting messages */
5505     if (message != WM_PAINT &&
5506         message != WM_NCPAINT &&
5507         message != WM_SYNCPAINT &&
5508         message != WM_ERASEBKGND &&
5509         message != WM_NCHITTEST &&
5510         message != WM_GETTEXT &&
5511         !ignore_message( message ))
5512     {
5513         msg.hwnd = hwnd;
5514         msg.message = message;
5515         msg.flags = sent|wparam|lparam;
5516         if (defwndproc_counter) msg.flags |= defwinproc;
5517         msg.wParam = wParam;
5518         msg.lParam = lParam;
5519         msg.descr = "combo";
5520         add_message(&msg);
5521     }
5522
5523     defwndproc_counter++;
5524     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5525     defwndproc_counter--;
5526
5527     return ret;
5528 }
5529
5530 static void subclass_combobox(void)
5531 {
5532     WNDCLASSA cls;
5533
5534     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5535
5536     old_combobox_proc = cls.lpfnWndProc;
5537
5538     cls.hInstance = GetModuleHandle(0);
5539     cls.lpfnWndProc = combobox_hook_proc;
5540     cls.lpszClassName = "my_combobox_class";
5541     UnregisterClass(cls.lpszClassName, cls.hInstance);
5542     if (!RegisterClassA(&cls)) assert(0);
5543 }
5544
5545 static void test_combobox_messages(void)
5546 {
5547     HWND parent, combo;
5548     LRESULT ret;
5549
5550     subclass_combobox();
5551
5552     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5553                              100, 100, 200, 200, 0, 0, 0, NULL);
5554     ok(parent != 0, "Failed to create parent window\n");
5555     flush_sequence();
5556
5557     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5558                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5559     ok(combo != 0, "Failed to create combobox window\n");
5560
5561     UpdateWindow(combo);
5562
5563     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5564     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5565
5566     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5567     ok(ret == 0, "expected 0, got %ld\n", ret);
5568     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5569     ok(ret == 1, "expected 1, got %ld\n", ret);
5570     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5571     ok(ret == 2, "expected 2, got %ld\n", ret);
5572
5573     SendMessage(combo, CB_SETCURSEL, 0, 0);
5574     SetFocus(combo);
5575     flush_sequence();
5576
5577     log_all_parent_messages++;
5578     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5579     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5580     log_all_parent_messages--;
5581     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5582
5583     DestroyWindow(combo);
5584     DestroyWindow(parent);
5585 }
5586
5587 /****************** WM_IME_KEYDOWN message test *******************/
5588
5589 static const struct message WmImeKeydownMsgSeq_0[] =
5590 {
5591     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5592     { WM_CHAR, wparam, 'A' },
5593     { 0 }
5594 };
5595
5596 static const struct message WmImeKeydownMsgSeq_1[] =
5597 {
5598     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5599     { WM_CHAR,    optional|wparam, VK_RETURN },
5600     { 0 }
5601 };
5602
5603 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5604 {
5605     struct recvd_message msg;
5606
5607     msg.hwnd = hwnd;
5608     msg.message = message;
5609     msg.flags = wparam|lparam;
5610     msg.wParam = wParam;
5611     msg.lParam = lParam;
5612     msg.descr = "wmime_keydown";
5613     add_message(&msg);
5614
5615     return DefWindowProcA(hwnd, message, wParam, lParam);
5616 }
5617
5618 static void register_wmime_keydown_class(void)
5619 {
5620     WNDCLASSA cls;
5621
5622     ZeroMemory(&cls, sizeof(WNDCLASSA));
5623     cls.lpfnWndProc = wmime_keydown_procA;
5624     cls.hInstance = GetModuleHandleA(0);
5625     cls.lpszClassName = "wmime_keydown_class";
5626     if (!RegisterClassA(&cls)) assert(0);
5627 }
5628
5629 static void test_wmime_keydown_message(void)
5630 {
5631     HWND hwnd;
5632     MSG msg;
5633
5634     trace("Message sequences by WM_IME_KEYDOWN\n");
5635
5636     register_wmime_keydown_class();
5637     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5638                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5639                            NULL, NULL, 0);
5640     flush_events();
5641     flush_sequence();
5642
5643     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5644     SendMessage(hwnd, WM_CHAR, 'A', 1);
5645     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5646
5647     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5648     {
5649         TranslateMessage(&msg);
5650         DispatchMessage(&msg);
5651     }
5652     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5653
5654     DestroyWindow(hwnd);
5655 }
5656
5657 /************* painting message test ********************/
5658
5659 void dump_region(HRGN hrgn)
5660 {
5661     DWORD i, size;
5662     RGNDATA *data = NULL;
5663     RECT *rect;
5664
5665     if (!hrgn)
5666     {
5667         printf( "null region\n" );
5668         return;
5669     }
5670     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5671     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5672     GetRegionData( hrgn, size, data );
5673     printf("%d rects:", data->rdh.nCount );
5674     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5675         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5676     printf("\n");
5677     HeapFree( GetProcessHeap(), 0, data );
5678 }
5679
5680 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5681 {
5682     INT ret;
5683     RECT r1, r2;
5684     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5685     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5686
5687     ret = GetUpdateRgn( hwnd, update, FALSE );
5688     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5689     if (ret == NULLREGION)
5690     {
5691         ok( !hrgn, "Update region shouldn't be empty\n" );
5692     }
5693     else
5694     {
5695         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5696         {
5697             ok( 0, "Regions are different\n" );
5698             if (winetest_debug > 0)
5699             {
5700                 printf( "Update region: " );
5701                 dump_region( update );
5702                 printf( "Wanted region: " );
5703                 dump_region( hrgn );
5704             }
5705         }
5706     }
5707     GetRgnBox( update, &r1 );
5708     GetUpdateRect( hwnd, &r2, FALSE );
5709     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5710         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5711         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5712
5713     DeleteObject( tmp );
5714     DeleteObject( update );
5715 }
5716
5717 static const struct message WmInvalidateRgn[] = {
5718     { WM_NCPAINT, sent },
5719     { WM_GETTEXT, sent|defwinproc|optional },
5720     { 0 }
5721 };
5722
5723 static const struct message WmGetUpdateRect[] = {
5724     { WM_NCPAINT, sent },
5725     { WM_GETTEXT, sent|defwinproc|optional },
5726     { WM_PAINT, sent },
5727     { 0 }
5728 };
5729
5730 static const struct message WmInvalidateFull[] = {
5731     { WM_NCPAINT, sent|wparam, 1 },
5732     { WM_GETTEXT, sent|defwinproc|optional },
5733     { 0 }
5734 };
5735
5736 static const struct message WmInvalidateErase[] = {
5737     { WM_NCPAINT, sent|wparam, 1 },
5738     { WM_GETTEXT, sent|defwinproc|optional },
5739     { WM_ERASEBKGND, sent },
5740     { 0 }
5741 };
5742
5743 static const struct message WmInvalidatePaint[] = {
5744     { WM_PAINT, sent },
5745     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5746     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5747     { 0 }
5748 };
5749
5750 static const struct message WmInvalidateErasePaint[] = {
5751     { WM_PAINT, sent },
5752     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5753     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5754     { WM_ERASEBKGND, sent|beginpaint|optional },
5755     { 0 }
5756 };
5757
5758 static const struct message WmInvalidateErasePaint2[] = {
5759     { WM_PAINT, sent },
5760     { WM_NCPAINT, sent|beginpaint },
5761     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5762     { WM_ERASEBKGND, sent|beginpaint|optional },
5763     { 0 }
5764 };
5765
5766 static const struct message WmErase[] = {
5767     { WM_ERASEBKGND, sent },
5768     { 0 }
5769 };
5770
5771 static const struct message WmPaint[] = {
5772     { WM_PAINT, sent },
5773     { 0 }
5774 };
5775
5776 static const struct message WmParentOnlyPaint[] = {
5777     { WM_PAINT, sent|parent },
5778     { 0 }
5779 };
5780
5781 static const struct message WmInvalidateParent[] = {
5782     { WM_NCPAINT, sent|parent },
5783     { WM_GETTEXT, sent|defwinproc|parent|optional },
5784     { WM_ERASEBKGND, sent|parent },
5785     { 0 }
5786 };
5787
5788 static const struct message WmInvalidateParentChild[] = {
5789     { WM_NCPAINT, sent|parent },
5790     { WM_GETTEXT, sent|defwinproc|parent|optional },
5791     { WM_ERASEBKGND, sent|parent },
5792     { WM_NCPAINT, sent },
5793     { WM_GETTEXT, sent|defwinproc|optional },
5794     { WM_ERASEBKGND, sent },
5795     { 0 }
5796 };
5797
5798 static const struct message WmInvalidateParentChild2[] = {
5799     { WM_ERASEBKGND, sent|parent },
5800     { WM_NCPAINT, sent },
5801     { WM_GETTEXT, sent|defwinproc|optional },
5802     { WM_ERASEBKGND, sent },
5803     { 0 }
5804 };
5805
5806 static const struct message WmParentPaint[] = {
5807     { WM_PAINT, sent|parent },
5808     { WM_PAINT, sent },
5809     { 0 }
5810 };
5811
5812 static const struct message WmParentPaintNc[] = {
5813     { WM_PAINT, sent|parent },
5814     { WM_PAINT, sent },
5815     { WM_NCPAINT, sent|beginpaint },
5816     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5817     { WM_ERASEBKGND, sent|beginpaint|optional },
5818     { 0 }
5819 };
5820
5821 static const struct message WmChildPaintNc[] = {
5822     { WM_PAINT, sent },
5823     { WM_NCPAINT, sent|beginpaint },
5824     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5825     { WM_ERASEBKGND, sent|beginpaint|optional },
5826     { 0 }
5827 };
5828
5829 static const struct message WmParentErasePaint[] = {
5830     { WM_PAINT, sent|parent },
5831     { WM_NCPAINT, sent|parent|beginpaint },
5832     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5833     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
5834     { WM_PAINT, sent },
5835     { WM_NCPAINT, sent|beginpaint },
5836     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5837     { WM_ERASEBKGND, sent|beginpaint|optional },
5838     { 0 }
5839 };
5840
5841 static const struct message WmParentOnlyNcPaint[] = {
5842     { WM_PAINT, sent|parent },
5843     { WM_NCPAINT, sent|parent|beginpaint },
5844     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5845     { 0 }
5846 };
5847
5848 static const struct message WmSetParentStyle[] = {
5849     { WM_STYLECHANGING, sent|parent },
5850     { WM_STYLECHANGED, sent|parent },
5851     { 0 }
5852 };
5853
5854 static void test_paint_messages(void)
5855 {
5856     BOOL ret;
5857     RECT rect;
5858     POINT pt;
5859     MSG msg;
5860     HWND hparent, hchild;
5861     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5862     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5863     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5864                                 100, 100, 200, 200, 0, 0, 0, NULL);
5865     ok (hwnd != 0, "Failed to create overlapped window\n");
5866
5867     ShowWindow( hwnd, SW_SHOW );
5868     UpdateWindow( hwnd );
5869     flush_events();
5870     flush_sequence();
5871
5872     check_update_rgn( hwnd, 0 );
5873     SetRectRgn( hrgn, 10, 10, 20, 20 );
5874     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5875     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5876     check_update_rgn( hwnd, hrgn );
5877     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5878     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5879     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5880     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5881     check_update_rgn( hwnd, hrgn );
5882     /* validate everything */
5883     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5884     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5885     check_update_rgn( hwnd, 0 );
5886
5887     /* test empty region */
5888     SetRectRgn( hrgn, 10, 10, 10, 15 );
5889     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5890     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5891     check_update_rgn( hwnd, 0 );
5892     /* test empty rect */
5893     SetRect( &rect, 10, 10, 10, 15 );
5894     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5895     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5896     check_update_rgn( hwnd, 0 );
5897
5898     /* flush pending messages */
5899     flush_events();
5900     flush_sequence();
5901
5902     GetClientRect( hwnd, &rect );
5903     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5904     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5905      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5906      */
5907     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5908     SetRectEmpty( &rect );
5909     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5910     check_update_rgn( hwnd, hrgn );
5911     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5912     flush_events();
5913     ok_sequence( WmPaint, "Paint", FALSE );
5914     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5915     check_update_rgn( hwnd, 0 );
5916
5917     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5918      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5919      */
5920     trace("testing ValidateRect(0, NULL)\n");
5921     SetRectEmpty( &rect );
5922     if (ValidateRect(0, &rect))  /* not supported on Win9x */
5923     {
5924         check_update_rgn( hwnd, hrgn );
5925         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5926         flush_events();
5927         ok_sequence( WmPaint, "Paint", FALSE );
5928         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5929         check_update_rgn( hwnd, 0 );
5930     }
5931
5932     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5933     SetLastError(0xdeadbeef);
5934     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5935     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5936        "wrong error code %d\n", GetLastError());
5937     check_update_rgn( hwnd, 0 );
5938     flush_events();
5939     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5940
5941     trace("testing ValidateRgn(0, NULL)\n");
5942     SetLastError(0xdeadbeef);
5943     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5944     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
5945        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
5946        "wrong error code %d\n", GetLastError());
5947     check_update_rgn( hwnd, 0 );
5948     flush_events();
5949     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5950
5951     /* now with frame */
5952     SetRectRgn( hrgn, -5, -5, 20, 20 );
5953
5954     /* flush pending messages */
5955     flush_events();
5956     flush_sequence();
5957     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5958     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5959
5960     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5961     check_update_rgn( hwnd, hrgn );
5962
5963     flush_sequence();
5964     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5965     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5966
5967     flush_sequence();
5968     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5969     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5970
5971     GetClientRect( hwnd, &rect );
5972     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5973     check_update_rgn( hwnd, hrgn );
5974
5975     flush_sequence();
5976     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5977     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5978
5979     flush_sequence();
5980     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5981     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5982     check_update_rgn( hwnd, 0 );
5983
5984     flush_sequence();
5985     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5986     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5987     check_update_rgn( hwnd, 0 );
5988
5989     flush_sequence();
5990     SetRectRgn( hrgn, 0, 0, 100, 100 );
5991     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5992     SetRectRgn( hrgn, 0, 0, 50, 100 );
5993     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5994     SetRectRgn( hrgn, 50, 0, 100, 100 );
5995     check_update_rgn( hwnd, hrgn );
5996     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5997     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5998     check_update_rgn( hwnd, 0 );
5999
6000     flush_sequence();
6001     SetRectRgn( hrgn, 0, 0, 100, 100 );
6002     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6003     SetRectRgn( hrgn, 0, 0, 100, 50 );
6004     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6005     ok_sequence( WmErase, "Erase", FALSE );
6006     SetRectRgn( hrgn, 0, 50, 100, 100 );
6007     check_update_rgn( hwnd, hrgn );
6008
6009     flush_sequence();
6010     SetRectRgn( hrgn, 0, 0, 100, 100 );
6011     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6012     SetRectRgn( hrgn, 0, 0, 50, 50 );
6013     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6014     ok_sequence( WmPaint, "Paint", FALSE );
6015
6016     flush_sequence();
6017     SetRectRgn( hrgn, -4, -4, -2, -2 );
6018     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6019     SetRectRgn( hrgn, -200, -200, -198, -198 );
6020     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6021     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6022
6023     flush_sequence();
6024     SetRectRgn( hrgn, -4, -4, -2, -2 );
6025     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6026     SetRectRgn( hrgn, -4, -4, -3, -3 );
6027     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6028     SetRectRgn( hrgn, 0, 0, 1, 1 );
6029     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6030     ok_sequence( WmPaint, "Paint", FALSE );
6031
6032     flush_sequence();
6033     SetRectRgn( hrgn, -4, -4, -1, -1 );
6034     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6035     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6036     /* make sure no WM_PAINT was generated */
6037     flush_events();
6038     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6039
6040     flush_sequence();
6041     SetRectRgn( hrgn, -4, -4, -1, -1 );
6042     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6043     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6044     {
6045         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6046         {
6047             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6048             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6049             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6050             ret = GetUpdateRect( hwnd, &rect, FALSE );
6051             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6052             /* this will send WM_NCPAINT and validate the non client area */
6053             ret = GetUpdateRect( hwnd, &rect, TRUE );
6054             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6055         }
6056         DispatchMessage( &msg );
6057     }
6058     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6059
6060     DestroyWindow( hwnd );
6061
6062     /* now test with a child window */
6063
6064     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6065                               100, 100, 200, 200, 0, 0, 0, NULL);
6066     ok (hparent != 0, "Failed to create parent window\n");
6067
6068     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6069                            10, 10, 100, 100, hparent, 0, 0, NULL);
6070     ok (hchild != 0, "Failed to create child window\n");
6071
6072     ShowWindow( hparent, SW_SHOW );
6073     UpdateWindow( hparent );
6074     UpdateWindow( hchild );
6075     flush_events();
6076     flush_sequence();
6077     log_all_parent_messages++;
6078
6079     SetRect( &rect, 0, 0, 50, 50 );
6080     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6081     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6082     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6083
6084     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6085     pt.x = pt.y = 0;
6086     MapWindowPoints( hchild, hparent, &pt, 1 );
6087     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6088     check_update_rgn( hchild, hrgn );
6089     SetRectRgn( hrgn, 0, 0, 50, 50 );
6090     check_update_rgn( hparent, hrgn );
6091     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6092     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6093     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6094     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6095
6096     flush_events();
6097     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6098
6099     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6100     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6101     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6102     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6103     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6104
6105     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6106     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6107     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6108
6109     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6110     flush_sequence();
6111     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6112     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6113     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6114
6115     /* flush all paint messages */
6116     flush_events();
6117     flush_sequence();
6118
6119     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6120     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6121     SetRectRgn( hrgn, 0, 0, 50, 50 );
6122     check_update_rgn( hparent, hrgn );
6123     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6124     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6125     SetRectRgn( hrgn, 0, 0, 50, 50 );
6126     check_update_rgn( hparent, hrgn );
6127
6128     /* flush all paint messages */
6129     flush_events();
6130     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6131     flush_sequence();
6132
6133     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6134     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6135     SetRectRgn( hrgn, 0, 0, 50, 50 );
6136     check_update_rgn( hparent, hrgn );
6137     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6138     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6139     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6140     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6141     check_update_rgn( hparent, hrgn );
6142     /* flush all paint messages */
6143     flush_events();
6144     flush_sequence();
6145
6146     /* same as above but parent gets completely validated */
6147     SetRect( &rect, 20, 20, 30, 30 );
6148     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6149     SetRectRgn( hrgn, 20, 20, 30, 30 );
6150     check_update_rgn( hparent, hrgn );
6151     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6152     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6153     check_update_rgn( hparent, 0 );  /* no update region */
6154     flush_events();
6155     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6156
6157     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6158     flush_sequence();
6159     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6160     SetRectRgn( hrgn, 20, 20, 30, 30 );
6161     check_update_rgn( hparent, hrgn );
6162     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6163     SetRectRgn( hrgn, 20, 20, 30, 30 );
6164     check_update_rgn( hparent, hrgn );
6165
6166     /* same as above but normal WM_PAINT doesn't validate parent */
6167     flush_sequence();
6168     SetRect( &rect, 20, 20, 30, 30 );
6169     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6170     SetRectRgn( hrgn, 20, 20, 30, 30 );
6171     check_update_rgn( hparent, hrgn );
6172     /* no WM_PAINT in child while parent still pending */
6173     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6174     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6175     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6176     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6177
6178     flush_sequence();
6179     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6180     /* no WM_PAINT in child while parent still pending */
6181     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6182     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6183     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6184     /* now that parent is valid child should get WM_PAINT */
6185     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6186     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6187     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6188     ok_sequence( WmEmptySeq, "No other message", FALSE );
6189
6190     /* same thing with WS_CLIPCHILDREN in parent */
6191     flush_sequence();
6192     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6193     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6194     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6195     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6196     ok_sequence( WmEmptySeq, "No message", FALSE );
6197     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6198     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6199
6200     flush_sequence();
6201     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6202     SetRectRgn( hrgn, 20, 20, 30, 30 );
6203     check_update_rgn( hparent, hrgn );
6204     /* no WM_PAINT in child while parent still pending */
6205     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6206     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6207     /* WM_PAINT in parent first */
6208     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6209     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6210
6211     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6212     flush_sequence();
6213     SetRect( &rect, 0, 0, 30, 30 );
6214     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6215     SetRectRgn( hrgn, 0, 0, 30, 30 );
6216     check_update_rgn( hparent, hrgn );
6217     flush_events();
6218     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6219
6220     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6221     flush_sequence();
6222     SetRect( &rect, -10, 0, 30, 30 );
6223     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6224     SetRect( &rect, 0, 0, 20, 20 );
6225     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6226     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6227     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6228
6229     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6230     flush_sequence();
6231     SetRect( &rect, -10, 0, 30, 30 );
6232     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6233     SetRect( &rect, 0, 0, 100, 100 );
6234     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6235     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6236     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6237     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6238     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6239
6240     /* test RDW_INTERNALPAINT behavior */
6241
6242     flush_sequence();
6243     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6244     flush_events();
6245     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6246
6247     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6248     flush_events();
6249     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6250
6251     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6252     flush_events();
6253     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6254
6255     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6256     UpdateWindow( hparent );
6257     flush_events();
6258     flush_sequence();
6259     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6260     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6261     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6262                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6263     flush_events();
6264     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6265
6266     UpdateWindow( hparent );
6267     flush_events();
6268     flush_sequence();
6269     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6270     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6271     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6272                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6273     flush_events();
6274     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6275
6276     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6277     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6278     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6279     flush_events();
6280     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6281
6282     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6283     UpdateWindow( hparent );
6284     flush_events();
6285     flush_sequence();
6286     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6287     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6288     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6289                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6290     flush_events();
6291     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6292
6293     UpdateWindow( hparent );
6294     flush_events();
6295     flush_sequence();
6296     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6297     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6298     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6299                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6300     flush_events();
6301     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6302
6303     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6304     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6305
6306     UpdateWindow( hparent );
6307     flush_events();
6308     flush_sequence();
6309     trace("testing SetWindowPos(-10000, -10000) on child\n");
6310     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6311     check_update_rgn( hchild, 0 );
6312     flush_events();
6313
6314 #if 0 /* this one doesn't pass under Wine yet */
6315     UpdateWindow( hparent );
6316     flush_events();
6317     flush_sequence();
6318     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6319     ShowWindow( hchild, SW_MINIMIZE );
6320     check_update_rgn( hchild, 0 );
6321     flush_events();
6322 #endif
6323
6324     UpdateWindow( hparent );
6325     flush_events();
6326     flush_sequence();
6327     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6328     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6329     check_update_rgn( hparent, 0 );
6330     flush_events();
6331
6332     log_all_parent_messages--;
6333     DestroyWindow( hparent );
6334     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6335
6336     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6337
6338     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6339                               100, 100, 200, 200, 0, 0, 0, NULL);
6340     ok (hparent != 0, "Failed to create parent window\n");
6341
6342     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6343                            10, 10, 100, 100, hparent, 0, 0, NULL);
6344     ok (hchild != 0, "Failed to create child window\n");
6345
6346     ShowWindow( hparent, SW_SHOW );
6347     UpdateWindow( hparent );
6348     UpdateWindow( hchild );
6349     flush_events();
6350     flush_sequence();
6351
6352     /* moving child outside of parent boundaries changes update region */
6353     SetRect( &rect, 0, 0, 40, 40 );
6354     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6355     SetRectRgn( hrgn, 0, 0, 40, 40 );
6356     check_update_rgn( hchild, hrgn );
6357     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6358     SetRectRgn( hrgn, 10, 0, 40, 40 );
6359     check_update_rgn( hchild, hrgn );
6360     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6361     SetRectRgn( hrgn, 10, 10, 40, 40 );
6362     check_update_rgn( hchild, hrgn );
6363
6364     /* moving parent off-screen does too */
6365     SetRect( &rect, 0, 0, 100, 100 );
6366     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6367     SetRectRgn( hrgn, 0, 0, 100, 100 );
6368     check_update_rgn( hparent, hrgn );
6369     SetRectRgn( hrgn, 10, 10, 40, 40 );
6370     check_update_rgn( hchild, hrgn );
6371     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6372     SetRectRgn( hrgn, 20, 20, 100, 100 );
6373     check_update_rgn( hparent, hrgn );
6374     SetRectRgn( hrgn, 30, 30, 40, 40 );
6375     check_update_rgn( hchild, hrgn );
6376
6377     /* invalidated region is cropped by the parent rects */
6378     SetRect( &rect, 0, 0, 50, 50 );
6379     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6380     SetRectRgn( hrgn, 30, 30, 50, 50 );
6381     check_update_rgn( hchild, hrgn );
6382
6383     DestroyWindow( hparent );
6384     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6385     flush_sequence();
6386
6387     DeleteObject( hrgn );
6388     DeleteObject( hrgn2 );
6389 }
6390
6391 struct wnd_event
6392 {
6393     HWND hwnd;
6394     HANDLE grand_child;
6395     HANDLE start_event;
6396     HANDLE stop_event;
6397 };
6398
6399 static DWORD WINAPI thread_proc(void *param)
6400 {
6401     MSG msg;
6402     struct wnd_event *wnd_event = param;
6403
6404     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6405                                       100, 100, 200, 200, 0, 0, 0, NULL);
6406     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6407
6408     SetEvent(wnd_event->start_event);
6409
6410     while (GetMessage(&msg, 0, 0, 0))
6411     {
6412         TranslateMessage(&msg);
6413         DispatchMessage(&msg);
6414     }
6415
6416     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6417
6418     return 0;
6419 }
6420
6421 static DWORD CALLBACK create_grand_child_thread( void *param )
6422 {
6423     struct wnd_event *wnd_event = param;
6424     HWND hchild;
6425     MSG msg;
6426
6427     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6428                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6429     ok (hchild != 0, "Failed to create child window\n");
6430     flush_events();
6431     flush_sequence();
6432     SetEvent( wnd_event->start_event );
6433
6434     for (;;)
6435     {
6436         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6437         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6438         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6439     }
6440     return 0;
6441 }
6442
6443 static DWORD CALLBACK create_child_thread( void *param )
6444 {
6445     struct wnd_event *wnd_event = param;
6446     struct wnd_event child_event;
6447     DWORD ret, tid;
6448     MSG msg;
6449
6450     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6451                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6452     ok (child_event.hwnd != 0, "Failed to create child window\n");
6453     SetFocus( child_event.hwnd );
6454     flush_events();
6455     flush_sequence();
6456     child_event.start_event = wnd_event->start_event;
6457     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6458     for (;;)
6459     {
6460         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6461         if (ret != 1) break;
6462         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6463     }
6464     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6465     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6466     return 0;
6467 }
6468
6469 static void test_interthread_messages(void)
6470 {
6471     HANDLE hThread;
6472     DWORD tid;
6473     WNDPROC proc;
6474     MSG msg;
6475     char buf[256];
6476     int len, expected_len;
6477     struct wnd_event wnd_event;
6478     BOOL ret;
6479
6480     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6481     if (!wnd_event.start_event)
6482     {
6483         win_skip("skipping interthread message test under win9x\n");
6484         return;
6485     }
6486
6487     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6488     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6489
6490     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6491
6492     CloseHandle(wnd_event.start_event);
6493
6494     SetLastError(0xdeadbeef);
6495     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6496     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6497        "wrong error code %d\n", GetLastError());
6498
6499     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6500     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6501
6502     expected_len = lstrlenA("window caption text");
6503     memset(buf, 0, sizeof(buf));
6504     SetLastError(0xdeadbeef);
6505     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6506     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6507     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6508
6509     msg.hwnd = wnd_event.hwnd;
6510     msg.message = WM_GETTEXT;
6511     msg.wParam = sizeof(buf);
6512     msg.lParam = (LPARAM)buf;
6513     memset(buf, 0, sizeof(buf));
6514     SetLastError(0xdeadbeef);
6515     len = DispatchMessageA(&msg);
6516     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6517        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6518
6519     /* the following test causes an exception in user.exe under win9x */
6520     msg.hwnd = wnd_event.hwnd;
6521     msg.message = WM_TIMER;
6522     msg.wParam = 0;
6523     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6524     SetLastError(0xdeadbeef);
6525     len = DispatchMessageA(&msg);
6526     ok(!len && GetLastError() == 0xdeadbeef,
6527        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6528
6529     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6530     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6531
6532     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6533     CloseHandle(hThread);
6534
6535     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6536
6537     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6538                               100, 100, 200, 200, 0, 0, 0, NULL);
6539     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6540     flush_sequence();
6541     log_all_parent_messages++;
6542     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6543     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6544     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6545     for (;;)
6546     {
6547         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6548         if (ret != 1) break;
6549         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6550     }
6551     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6552     /* now wait for the thread without processing messages; this shouldn't deadlock */
6553     SetEvent( wnd_event.stop_event );
6554     ret = WaitForSingleObject( hThread, 5000 );
6555     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6556     CloseHandle( hThread );
6557
6558     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6559     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6560     CloseHandle( wnd_event.grand_child );
6561
6562     CloseHandle( wnd_event.start_event );
6563     CloseHandle( wnd_event.stop_event );
6564     flush_events();
6565     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6566     log_all_parent_messages--;
6567     DestroyWindow( wnd_event.hwnd );
6568 }
6569
6570
6571 static const struct message WmVkN[] = {
6572     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6573     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6574     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6575     { WM_CHAR, wparam|lparam, 'n', 1 },
6576     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6577     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6578     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6579     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6580     { 0 }
6581 };
6582 static const struct message WmShiftVkN[] = {
6583     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6584     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6585     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6586     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6587     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6588     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6589     { WM_CHAR, wparam|lparam, 'N', 1 },
6590     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6591     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6592     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6593     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6594     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6595     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6596     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6597     { 0 }
6598 };
6599 static const struct message WmCtrlVkN[] = {
6600     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6601     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6602     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6603     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6604     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6605     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6606     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6607     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6608     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6609     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6610     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6611     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6612     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6613     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6614     { 0 }
6615 };
6616 static const struct message WmCtrlVkN_2[] = {
6617     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6618     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6619     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6620     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6621     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6622     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6623     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6624     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6625     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6626     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6627     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6628     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6629     { 0 }
6630 };
6631 static const struct message WmAltVkN[] = {
6632     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6633     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6634     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6635     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6636     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6637     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6638     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6639     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6640     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6641     { HCBT_SYSCOMMAND, hook },
6642     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6643     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6644     { 0x00AE, sent|defwinproc|optional }, /* XP */
6645     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6646     { WM_INITMENU, sent|defwinproc },
6647     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6648     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6649     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6650     { WM_CAPTURECHANGED, sent|defwinproc },
6651     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6652     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6653     { WM_EXITMENULOOP, sent|defwinproc },
6654     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6655     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6656     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6657     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6658     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6659     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6660     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6661     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6662     { 0 }
6663 };
6664 static const struct message WmAltVkN_2[] = {
6665     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6666     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6667     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6668     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6669     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6670     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6671     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6672     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6673     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6674     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6675     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6676     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6677     { 0 }
6678 };
6679 static const struct message WmCtrlAltVkN[] = {
6680     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6681     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6682     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6683     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6684     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6685     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6686     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6687     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6688     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6689     { WM_CHAR, optional },
6690     { WM_CHAR, sent|optional },
6691     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6692     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6693     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6694     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6695     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6696     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6697     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6698     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6699     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6700     { 0 }
6701 };
6702 static const struct message WmCtrlShiftVkN[] = {
6703     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6704     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6705     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6706     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6707     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6708     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6709     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6710     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6711     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6712     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6713     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6714     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6715     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6716     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6717     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6718     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6719     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6720     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6721     { 0 }
6722 };
6723 static const struct message WmCtrlAltShiftVkN[] = {
6724     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6725     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6726     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6727     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6728     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6729     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6730     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6731     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6732     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6733     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6734     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6735     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6736     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6737     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6738     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6739     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6740     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6741     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6742     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6743     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6744     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6745     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6746     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6747     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6748     { 0 }
6749 };
6750 static const struct message WmAltPressRelease[] = {
6751     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6752     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6753     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6754     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6755     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6756     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6757     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6758     { HCBT_SYSCOMMAND, hook },
6759     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6760     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6761     { WM_INITMENU, sent|defwinproc },
6762     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6763     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6764     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6765
6766     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6767
6768     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6769     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6770     { WM_CAPTURECHANGED, sent|defwinproc },
6771     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6772     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6773     { WM_EXITMENULOOP, sent|defwinproc },
6774     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6775     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6776     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6777     { 0 }
6778 };
6779 static const struct message WmShiftMouseButton[] = {
6780     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6781     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6782     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6783     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6784     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6785     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
6786     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
6787     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
6788     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
6789     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6790     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6791     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6792     { 0 }
6793 };
6794 static const struct message WmF1Seq[] = {
6795     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6796     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6797     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6798     { WM_KEYF1, wparam|lparam, 0, 0 },
6799     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6800     { WM_HELP, sent|defwinproc },
6801     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6802     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6803     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6804     { 0 }
6805 };
6806 static const struct message WmVkAppsSeq[] = {
6807     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6808     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6809     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6810     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6811     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6812     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6813     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6814     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6815     { 0 }
6816 };
6817
6818 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6819 {
6820     MSG msg;
6821
6822     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6823     {
6824         struct recvd_message log_msg;
6825
6826         /* ignore some unwanted messages */
6827         if (msg.message == WM_MOUSEMOVE ||
6828             msg.message == WM_TIMER ||
6829             ignore_message( msg.message ))
6830             continue;
6831
6832         log_msg.hwnd = msg.hwnd;
6833         log_msg.message = msg.message;
6834         log_msg.flags = wparam|lparam;
6835         log_msg.wParam = msg.wParam;
6836         log_msg.lParam = msg.lParam;
6837         log_msg.descr = "accel";
6838         add_message(&log_msg);
6839
6840         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6841         {
6842             TranslateMessage(&msg);
6843             DispatchMessage(&msg);
6844         }
6845     }
6846 }
6847
6848 static void test_accelerators(void)
6849 {
6850     RECT rc;
6851     POINT pt;
6852     SHORT state;
6853     HACCEL hAccel;
6854     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6855                                 100, 100, 200, 200, 0, 0, 0, NULL);
6856     BOOL ret;
6857
6858     assert(hwnd != 0);
6859     UpdateWindow(hwnd);
6860     flush_events();
6861     flush_sequence();
6862
6863     SetFocus(hwnd);
6864     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6865
6866     state = GetKeyState(VK_SHIFT);
6867     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6868     state = GetKeyState(VK_CAPITAL);
6869     ok(state == 0, "wrong CapsLock state %04x\n", state);
6870
6871     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6872     assert(hAccel != 0);
6873
6874     flush_events();
6875     pump_msg_loop(hwnd, 0);
6876     flush_sequence();
6877
6878     trace("testing VK_N press/release\n");
6879     flush_sequence();
6880     keybd_event('N', 0, 0, 0);
6881     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6882     pump_msg_loop(hwnd, hAccel);
6883     if (!sequence_cnt)  /* we didn't get any message */
6884     {
6885         skip( "queuing key events not supported\n" );
6886         goto done;
6887     }
6888     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6889
6890     trace("testing Shift+VK_N press/release\n");
6891     flush_sequence();
6892     keybd_event(VK_SHIFT, 0, 0, 0);
6893     keybd_event('N', 0, 0, 0);
6894     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6895     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6896     pump_msg_loop(hwnd, hAccel);
6897     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6898
6899     trace("testing Ctrl+VK_N press/release\n");
6900     flush_sequence();
6901     keybd_event(VK_CONTROL, 0, 0, 0);
6902     keybd_event('N', 0, 0, 0);
6903     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6904     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6905     pump_msg_loop(hwnd, hAccel);
6906     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6907
6908     trace("testing Alt+VK_N press/release\n");
6909     flush_sequence();
6910     keybd_event(VK_MENU, 0, 0, 0);
6911     keybd_event('N', 0, 0, 0);
6912     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6913     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6914     pump_msg_loop(hwnd, hAccel);
6915     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6916
6917     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6918     flush_sequence();
6919     keybd_event(VK_CONTROL, 0, 0, 0);
6920     keybd_event(VK_MENU, 0, 0, 0);
6921     keybd_event('N', 0, 0, 0);
6922     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6923     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6924     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6925     pump_msg_loop(hwnd, hAccel);
6926     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6927
6928     ret = DestroyAcceleratorTable(hAccel);
6929     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6930
6931     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6932     assert(hAccel != 0);
6933
6934     trace("testing VK_N press/release\n");
6935     flush_sequence();
6936     keybd_event('N', 0, 0, 0);
6937     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6938     pump_msg_loop(hwnd, hAccel);
6939     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6940
6941     trace("testing Shift+VK_N press/release\n");
6942     flush_sequence();
6943     keybd_event(VK_SHIFT, 0, 0, 0);
6944     keybd_event('N', 0, 0, 0);
6945     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6946     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6947     pump_msg_loop(hwnd, hAccel);
6948     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6949
6950     trace("testing Ctrl+VK_N press/release 2\n");
6951     flush_sequence();
6952     keybd_event(VK_CONTROL, 0, 0, 0);
6953     keybd_event('N', 0, 0, 0);
6954     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6955     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6956     pump_msg_loop(hwnd, hAccel);
6957     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6958
6959     trace("testing Alt+VK_N press/release 2\n");
6960     flush_sequence();
6961     keybd_event(VK_MENU, 0, 0, 0);
6962     keybd_event('N', 0, 0, 0);
6963     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6964     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6965     pump_msg_loop(hwnd, hAccel);
6966     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6967
6968     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6969     flush_sequence();
6970     keybd_event(VK_CONTROL, 0, 0, 0);
6971     keybd_event(VK_MENU, 0, 0, 0);
6972     keybd_event('N', 0, 0, 0);
6973     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6974     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6975     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6976     pump_msg_loop(hwnd, hAccel);
6977     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6978
6979     trace("testing Ctrl+Shift+VK_N press/release\n");
6980     flush_sequence();
6981     keybd_event(VK_CONTROL, 0, 0, 0);
6982     keybd_event(VK_SHIFT, 0, 0, 0);
6983     keybd_event('N', 0, 0, 0);
6984     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6985     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6986     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6987     pump_msg_loop(hwnd, hAccel);
6988     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6989
6990     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6991     flush_sequence();
6992     keybd_event(VK_CONTROL, 0, 0, 0);
6993     keybd_event(VK_MENU, 0, 0, 0);
6994     keybd_event(VK_SHIFT, 0, 0, 0);
6995     keybd_event('N', 0, 0, 0);
6996     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6997     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6998     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6999     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7000     pump_msg_loop(hwnd, hAccel);
7001     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7002
7003     ret = DestroyAcceleratorTable(hAccel);
7004     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7005     hAccel = 0;
7006
7007     trace("testing Alt press/release\n");
7008     flush_sequence();
7009     keybd_event(VK_MENU, 0, 0, 0);
7010     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7011     keybd_event(VK_MENU, 0, 0, 0);
7012     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7013     pump_msg_loop(hwnd, 0);
7014     /* this test doesn't pass in Wine for managed windows */
7015     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7016
7017     trace("testing VK_F1 press/release\n");
7018     keybd_event(VK_F1, 0, 0, 0);
7019     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7020     pump_msg_loop(hwnd, 0);
7021     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7022
7023     trace("testing VK_APPS press/release\n");
7024     keybd_event(VK_APPS, 0, 0, 0);
7025     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7026     pump_msg_loop(hwnd, 0);
7027     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7028
7029     trace("testing Shift+MouseButton press/release\n");
7030     /* first, move mouse pointer inside of the window client area */
7031     GetClientRect(hwnd, &rc);
7032     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7033     rc.left += (rc.right - rc.left)/2;
7034     rc.top += (rc.bottom - rc.top)/2;
7035     SetCursorPos(rc.left, rc.top);
7036     SetActiveWindow(hwnd);
7037
7038     flush_events();
7039     flush_sequence();
7040     GetCursorPos(&pt);
7041     if (pt.x == rc.left && pt.y == rc.top)
7042     {
7043         int i;
7044         keybd_event(VK_SHIFT, 0, 0, 0);
7045         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7046         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7047         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7048         pump_msg_loop(hwnd, 0);
7049         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7050         if (i < sequence_cnt)
7051             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7052         else
7053             skip( "Shift+MouseButton event didn't get to the window\n" );
7054     }
7055
7056 done:
7057     if (hAccel) DestroyAcceleratorTable(hAccel);
7058     DestroyWindow(hwnd);
7059 }
7060
7061 /************* window procedures ********************/
7062
7063 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
7064                              WPARAM wParam, LPARAM lParam)
7065 {
7066     static LONG defwndproc_counter = 0;
7067     static LONG beginpaint_counter = 0;
7068     LRESULT ret;
7069     struct recvd_message msg;
7070
7071     if (ignore_message( message )) return 0;
7072
7073     switch (message)
7074     {
7075         case WM_ENABLE:
7076         {
7077             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7078             ok((BOOL)wParam == !(style & WS_DISABLED),
7079                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7080             break;
7081         }
7082
7083         case WM_CAPTURECHANGED:
7084             if (test_DestroyWindow_flag)
7085             {
7086                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7087                 if (style & WS_CHILD)
7088                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7089                 else if (style & WS_POPUP)
7090                     lParam = WND_POPUP_ID;
7091                 else
7092                     lParam = WND_PARENT_ID;
7093             }
7094             break;
7095
7096         case WM_NCDESTROY:
7097         {
7098             HWND capture;
7099
7100             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7101             capture = GetCapture();
7102             if (capture)
7103             {
7104                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7105                 trace("current capture %p, releasing...\n", capture);
7106                 ReleaseCapture();
7107             }
7108         }
7109         /* fall through */
7110         case WM_DESTROY:
7111             if (pGetAncestor)
7112                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7113             if (test_DestroyWindow_flag)
7114             {
7115                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7116                 if (style & WS_CHILD)
7117                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7118                 else if (style & WS_POPUP)
7119                     lParam = WND_POPUP_ID;
7120                 else
7121                     lParam = WND_PARENT_ID;
7122             }
7123             break;
7124
7125         /* test_accelerators() depends on this */
7126         case WM_NCHITTEST:
7127             return HTCLIENT;
7128
7129         /* ignore */
7130         case WM_MOUSEMOVE:
7131         case WM_MOUSEACTIVATE:
7132         case WM_NCMOUSEMOVE:
7133         case WM_SETCURSOR:
7134         case WM_IME_SELECT:
7135             return 0;
7136     }
7137
7138     msg.hwnd = hwnd;
7139     msg.message = message;
7140     msg.flags = sent|wparam|lparam;
7141     if (defwndproc_counter) msg.flags |= defwinproc;
7142     if (beginpaint_counter) msg.flags |= beginpaint;
7143     msg.wParam = wParam;
7144     msg.lParam = lParam;
7145     msg.descr = "MsgCheckProc";
7146     add_message(&msg);
7147
7148     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7149     {
7150         HWND parent = GetParent(hwnd);
7151         RECT rc;
7152         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7153
7154         GetClientRect(parent, &rc);
7155         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7156         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7157               minmax->ptReserved.x, minmax->ptReserved.y,
7158               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7159               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7160               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7161               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7162
7163         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7164            minmax->ptMaxSize.x, rc.right);
7165         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7166            minmax->ptMaxSize.y, rc.bottom);
7167     }
7168
7169     if (message == WM_PAINT)
7170     {
7171         PAINTSTRUCT ps;
7172         beginpaint_counter++;
7173         BeginPaint( hwnd, &ps );
7174         beginpaint_counter--;
7175         EndPaint( hwnd, &ps );
7176         return 0;
7177     }
7178
7179     defwndproc_counter++;
7180     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7181                   : DefWindowProcA(hwnd, message, wParam, lParam);
7182     defwndproc_counter--;
7183
7184     return ret;
7185 }
7186
7187 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7188 {
7189     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7190 }
7191
7192 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7193 {
7194     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7195 }
7196
7197 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7198 {
7199     static LONG defwndproc_counter = 0;
7200     LRESULT ret;
7201     struct recvd_message msg;
7202
7203     if (ignore_message( message )) return 0;
7204
7205     switch (message)
7206     {
7207     case WM_QUERYENDSESSION:
7208     case WM_ENDSESSION:
7209         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7210         break;
7211     }
7212
7213     msg.hwnd = hwnd;
7214     msg.message = message;
7215     msg.flags = sent|wparam|lparam;
7216     if (defwndproc_counter) msg.flags |= defwinproc;
7217     msg.wParam = wParam;
7218     msg.lParam = lParam;
7219     msg.descr = "popup";
7220     add_message(&msg);
7221
7222     if (message == WM_CREATE)
7223     {
7224         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7225         SetWindowLongA(hwnd, GWL_STYLE, style);
7226     }
7227
7228     defwndproc_counter++;
7229     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7230     defwndproc_counter--;
7231
7232     return ret;
7233 }
7234
7235 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7236 {
7237     static LONG defwndproc_counter = 0;
7238     static LONG beginpaint_counter = 0;
7239     LRESULT ret;
7240     struct recvd_message msg;
7241
7242     if (ignore_message( message )) return 0;
7243
7244     if (log_all_parent_messages ||
7245         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7246         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7247         message == WM_ENABLE || message == WM_ENTERIDLE ||
7248         message == WM_DRAWITEM || message == WM_COMMAND ||
7249         message == WM_IME_SETCONTEXT)
7250     {
7251         switch (message)
7252         {
7253             /* ignore */
7254             case WM_NCHITTEST:
7255                 return HTCLIENT;
7256             case WM_SETCURSOR:
7257             case WM_MOUSEMOVE:
7258             case WM_NCMOUSEMOVE:
7259                 return 0;
7260
7261             case WM_ERASEBKGND:
7262             {
7263                 RECT rc;
7264                 INT ret = GetClipBox((HDC)wParam, &rc);
7265
7266                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7267                        ret, rc.left, rc.top, rc.right, rc.bottom);
7268                 break;
7269             }
7270         }
7271
7272         msg.hwnd = hwnd;
7273         msg.message = message;
7274         msg.flags = sent|parent|wparam|lparam;
7275         if (defwndproc_counter) msg.flags |= defwinproc;
7276         if (beginpaint_counter) msg.flags |= beginpaint;
7277         msg.wParam = wParam;
7278         msg.lParam = lParam;
7279         msg.descr = "parent";
7280         add_message(&msg);
7281     }
7282
7283     if (message == WM_PAINT)
7284     {
7285         PAINTSTRUCT ps;
7286         beginpaint_counter++;
7287         BeginPaint( hwnd, &ps );
7288         beginpaint_counter--;
7289         EndPaint( hwnd, &ps );
7290         return 0;
7291     }
7292
7293     defwndproc_counter++;
7294     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7295     defwndproc_counter--;
7296
7297     return ret;
7298 }
7299
7300 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7301 {
7302     static LONG defwndproc_counter = 0;
7303     LRESULT ret;
7304     struct recvd_message msg;
7305
7306     if (ignore_message( message )) return 0;
7307
7308     if (test_def_id)
7309     {
7310         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7311         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7312         if (after_end_dialog)
7313             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7314         else
7315             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7316     }
7317
7318     msg.hwnd = hwnd;
7319     msg.message = message;
7320     msg.flags = sent|wparam|lparam;
7321     if (defwndproc_counter) msg.flags |= defwinproc;
7322     msg.wParam = wParam;
7323     msg.lParam = lParam;
7324     msg.descr = "dialog";
7325     add_message(&msg);
7326
7327     defwndproc_counter++;
7328     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7329     defwndproc_counter--;
7330
7331     return ret;
7332 }
7333
7334 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7335 {
7336     static LONG defwndproc_counter = 0;
7337     LRESULT ret;
7338     struct recvd_message msg;
7339
7340     /* log only specific messages we are interested in */
7341     switch (message)
7342     {
7343 #if 0 /* probably log these as well */
7344     case WM_ACTIVATE:
7345     case WM_SETFOCUS:
7346     case WM_KILLFOCUS:
7347 #endif
7348     case WM_SHOWWINDOW:
7349     case WM_SIZE:
7350     case WM_MOVE:
7351     case WM_GETMINMAXINFO:
7352     case WM_WINDOWPOSCHANGING:
7353     case WM_WINDOWPOSCHANGED:
7354         break;
7355
7356     default: /* ignore */
7357         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7358         return DefWindowProcA(hwnd, message, wParam, lParam);
7359     }
7360
7361     msg.hwnd = hwnd;
7362     msg.message = message;
7363     msg.flags = sent|wparam|lparam;
7364     if (defwndproc_counter) msg.flags |= defwinproc;
7365     msg.wParam = wParam;
7366     msg.lParam = lParam;
7367     msg.descr = "show";
7368     add_message(&msg);
7369
7370     defwndproc_counter++;
7371     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7372     defwndproc_counter--;
7373
7374     return ret;
7375 }
7376
7377 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7378 {
7379     switch (msg)
7380     {
7381         case WM_CREATE: return 0;
7382         case WM_PAINT:
7383         {
7384             MSG msg2;
7385             static int i = 0;
7386
7387             if (i < 256)
7388             {
7389                 i++;
7390                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7391                 {
7392                     TranslateMessage(&msg2);
7393                     DispatchMessage(&msg2);
7394                 }
7395                 i--;
7396             }
7397             else ok(broken(1), "infinite loop\n");
7398             if ( i == 0)
7399                 paint_loop_done = 1;
7400             return DefWindowProcA(hWnd,msg,wParam,lParam);
7401         }
7402     }
7403     return DefWindowProcA(hWnd,msg,wParam,lParam);
7404 }
7405
7406 static BOOL RegisterWindowClasses(void)
7407 {
7408     WNDCLASSA cls;
7409     WNDCLASSW clsW;
7410
7411     cls.style = 0;
7412     cls.lpfnWndProc = MsgCheckProcA;
7413     cls.cbClsExtra = 0;
7414     cls.cbWndExtra = 0;
7415     cls.hInstance = GetModuleHandleA(0);
7416     cls.hIcon = 0;
7417     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7418     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7419     cls.lpszMenuName = NULL;
7420     cls.lpszClassName = "TestWindowClass";
7421     if(!RegisterClassA(&cls)) return FALSE;
7422
7423     cls.lpfnWndProc = ShowWindowProcA;
7424     cls.lpszClassName = "ShowWindowClass";
7425     if(!RegisterClassA(&cls)) return FALSE;
7426
7427     cls.lpfnWndProc = PopupMsgCheckProcA;
7428     cls.lpszClassName = "TestPopupClass";
7429     if(!RegisterClassA(&cls)) return FALSE;
7430
7431     cls.lpfnWndProc = ParentMsgCheckProcA;
7432     cls.lpszClassName = "TestParentClass";
7433     if(!RegisterClassA(&cls)) return FALSE;
7434
7435     cls.lpfnWndProc = DefWindowProcA;
7436     cls.lpszClassName = "SimpleWindowClass";
7437     if(!RegisterClassA(&cls)) return FALSE;
7438
7439     cls.lpfnWndProc = PaintLoopProcA;
7440     cls.lpszClassName = "PaintLoopWindowClass";
7441     if(!RegisterClassA(&cls)) return FALSE;
7442
7443     cls.style = CS_NOCLOSE;
7444     cls.lpszClassName = "NoCloseWindowClass";
7445     if(!RegisterClassA(&cls)) return FALSE;
7446
7447     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7448     cls.style = 0;
7449     cls.hInstance = GetModuleHandleA(0);
7450     cls.hbrBackground = 0;
7451     cls.lpfnWndProc = TestDlgProcA;
7452     cls.lpszClassName = "TestDialogClass";
7453     if(!RegisterClassA(&cls)) return FALSE;
7454
7455     clsW.style = 0;
7456     clsW.lpfnWndProc = MsgCheckProcW;
7457     clsW.cbClsExtra = 0;
7458     clsW.cbWndExtra = 0;
7459     clsW.hInstance = GetModuleHandleW(0);
7460     clsW.hIcon = 0;
7461     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7462     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7463     clsW.lpszMenuName = NULL;
7464     clsW.lpszClassName = testWindowClassW;
7465     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7466
7467     return TRUE;
7468 }
7469
7470 static BOOL is_our_logged_class(HWND hwnd)
7471 {
7472     char buf[256];
7473
7474     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7475     {
7476         if (!lstrcmpiA(buf, "TestWindowClass") ||
7477             !lstrcmpiA(buf, "ShowWindowClass") ||
7478             !lstrcmpiA(buf, "TestParentClass") ||
7479             !lstrcmpiA(buf, "TestPopupClass") ||
7480             !lstrcmpiA(buf, "SimpleWindowClass") ||
7481             !lstrcmpiA(buf, "TestDialogClass") ||
7482             !lstrcmpiA(buf, "MDI_frame_class") ||
7483             !lstrcmpiA(buf, "MDI_client_class") ||
7484             !lstrcmpiA(buf, "MDI_child_class") ||
7485             !lstrcmpiA(buf, "my_button_class") ||
7486             !lstrcmpiA(buf, "my_edit_class") ||
7487             !lstrcmpiA(buf, "static") ||
7488             !lstrcmpiA(buf, "ListBox") ||
7489             !lstrcmpiA(buf, "ComboBox") ||
7490             !lstrcmpiA(buf, "MyDialogClass") ||
7491             !lstrcmpiA(buf, "#32770") ||
7492             !lstrcmpiA(buf, "#32768"))
7493         return TRUE;
7494     }
7495     return FALSE;
7496 }
7497
7498 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7499
7500     HWND hwnd;
7501
7502     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7503
7504     if (nCode == HCBT_CLICKSKIPPED)
7505     {
7506         /* ignore this event, XP sends it a lot when switching focus between windows */
7507         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7508     }
7509
7510     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7511     {
7512         struct recvd_message msg;
7513
7514         msg.hwnd = 0;
7515         msg.message = nCode;
7516         msg.flags = hook|wparam|lparam;
7517         msg.wParam = wParam;
7518         msg.lParam = lParam;
7519         msg.descr = "CBT";
7520         add_message(&msg);
7521
7522         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7523     }
7524
7525     if (nCode == HCBT_DESTROYWND)
7526     {
7527         if (test_DestroyWindow_flag)
7528         {
7529             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7530             if (style & WS_CHILD)
7531                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7532             else if (style & WS_POPUP)
7533                 lParam = WND_POPUP_ID;
7534             else
7535                 lParam = WND_PARENT_ID;
7536         }
7537     }
7538
7539     /* Log also SetFocus(0) calls */
7540     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7541
7542     if (is_our_logged_class(hwnd))
7543     {
7544         struct recvd_message msg;
7545
7546         msg.hwnd = hwnd;
7547         msg.message = nCode;
7548         msg.flags = hook|wparam|lparam;
7549         msg.wParam = wParam;
7550         msg.lParam = lParam;
7551         msg.descr = "CBT";
7552         add_message(&msg);
7553     }
7554     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7555 }
7556
7557 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7558                                     DWORD event,
7559                                     HWND hwnd,
7560                                     LONG object_id,
7561                                     LONG child_id,
7562                                     DWORD thread_id,
7563                                     DWORD event_time)
7564 {
7565     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7566
7567     /* ignore mouse cursor events */
7568     if (object_id == OBJID_CURSOR) return;
7569
7570     if (!hwnd || is_our_logged_class(hwnd))
7571     {
7572         struct recvd_message msg;
7573
7574         msg.hwnd = hwnd;
7575         msg.message = event;
7576         msg.flags = winevent_hook|wparam|lparam;
7577         msg.wParam = object_id;
7578         msg.lParam = child_id;
7579         msg.descr = "WEH";
7580         add_message(&msg);
7581     }
7582 }
7583
7584 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7585 static const WCHAR wszAnsi[] = {'U',0};
7586
7587 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7588 {
7589     switch (uMsg)
7590     {
7591     case CB_FINDSTRINGEXACT:
7592         trace("String: %p\n", (LPCWSTR)lParam);
7593         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7594             return 1;
7595         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7596             return 0;
7597         return -1;
7598     }
7599     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7600 }
7601
7602 static const struct message WmGetTextLengthAfromW[] = {
7603     { WM_GETTEXTLENGTH, sent },
7604     { WM_GETTEXT, sent|optional },
7605     { 0 }
7606 };
7607
7608 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7609
7610 /* dummy window proc for WM_GETTEXTLENGTH test */
7611 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7612 {
7613     switch(msg)
7614     {
7615     case WM_GETTEXTLENGTH:
7616         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7617     case WM_GETTEXT:
7618         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7619         return lstrlenW( (LPWSTR)lp );
7620     default:
7621         return DefWindowProcW( hwnd, msg, wp, lp );
7622     }
7623 }
7624
7625 static void test_message_conversion(void)
7626 {
7627     static const WCHAR wszMsgConversionClass[] =
7628         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7629     WNDCLASSW cls;
7630     LRESULT lRes;
7631     HWND hwnd;
7632     WNDPROC wndproc, newproc;
7633     BOOL ret;
7634
7635     cls.style = 0;
7636     cls.lpfnWndProc = MsgConversionProcW;
7637     cls.cbClsExtra = 0;
7638     cls.cbWndExtra = 0;
7639     cls.hInstance = GetModuleHandleW(NULL);
7640     cls.hIcon = NULL;
7641     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7642     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7643     cls.lpszMenuName = NULL;
7644     cls.lpszClassName = wszMsgConversionClass;
7645     /* this call will fail on Win9x, but that doesn't matter as this test is
7646      * meaningless on those platforms */
7647     if(!RegisterClassW(&cls)) return;
7648
7649     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7650                            100, 100, 200, 200, 0, 0, 0, NULL);
7651     ok(hwnd != NULL, "Window creation failed\n");
7652
7653     /* {W, A} -> A */
7654
7655     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7656     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7657     ok(lRes == 0, "String should have been converted\n");
7658     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7659     ok(lRes == 1, "String shouldn't have been converted\n");
7660
7661     /* {W, A} -> W */
7662
7663     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7664     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7665     ok(lRes == 1, "String shouldn't have been converted\n");
7666     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7667     ok(lRes == 1, "String shouldn't have been converted\n");
7668
7669     /* Synchronous messages */
7670
7671     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7672     ok(lRes == 0, "String should have been converted\n");
7673     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7674     ok(lRes == 1, "String shouldn't have been converted\n");
7675
7676     /* Asynchronous messages */
7677
7678     SetLastError(0);
7679     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7680     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7681         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7682     SetLastError(0);
7683     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7684     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7685         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7686     SetLastError(0);
7687     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7688     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7689         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7690     SetLastError(0);
7691     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7692     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7693         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7694     SetLastError(0);
7695     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7696     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7697         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7698     SetLastError(0);
7699     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7700     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7701         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7702     SetLastError(0);
7703     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7704     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7705         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7706     SetLastError(0);
7707     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7708     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7709         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7710
7711     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7712
7713     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7714                           WS_OVERLAPPEDWINDOW,
7715                           100, 100, 200, 200, 0, 0, 0, NULL);
7716     assert(hwnd);
7717     flush_sequence();
7718     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7719     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7720     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7721         "got bad length %ld\n", lRes );
7722
7723     flush_sequence();
7724     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7725                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7726     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7727     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7728         "got bad length %ld\n", lRes );
7729
7730     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7731     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7732     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7733     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7734                                      NULL, 0, NULL, NULL ) ||
7735         broken(lRes == lstrlenW(dummy_window_text) + 37),
7736         "got bad length %ld\n", lRes );
7737
7738     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7739     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7740     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7741                                      NULL, 0, NULL, NULL ) ||
7742         broken(lRes == lstrlenW(dummy_window_text) + 37),
7743         "got bad length %ld\n", lRes );
7744
7745     ret = DestroyWindow(hwnd);
7746     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7747 }
7748
7749 struct timer_info
7750 {
7751     HWND hWnd;
7752     HANDLE handles[2];
7753     DWORD id;
7754 };
7755
7756 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7757 {
7758 }
7759
7760 #define TIMER_ID  0x19
7761
7762 static DWORD WINAPI timer_thread_proc(LPVOID x)
7763 {
7764     struct timer_info *info = x;
7765     DWORD r;
7766
7767     r = KillTimer(info->hWnd, 0x19);
7768     ok(r,"KillTimer failed in thread\n");
7769     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7770     ok(r,"SetTimer failed in thread\n");
7771     ok(r==TIMER_ID,"SetTimer id different\n");
7772     r = SetEvent(info->handles[0]);
7773     ok(r,"SetEvent failed in thread\n");
7774     return 0;
7775 }
7776
7777 static void test_timers(void)
7778 {
7779     struct timer_info info;
7780     DWORD id;
7781
7782     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7783        WS_OVERLAPPEDWINDOW ,
7784        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7785        NULL, NULL, 0);
7786
7787     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7788     ok(info.id, "SetTimer failed\n");
7789     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7790     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7791     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7792
7793     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7794
7795     WaitForSingleObject(info.handles[1], INFINITE);
7796
7797     CloseHandle(info.handles[0]);
7798     CloseHandle(info.handles[1]);
7799
7800     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7801
7802     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7803 }
7804
7805 static int count = 0;
7806 static VOID CALLBACK callback_count(
7807     HWND hwnd,
7808     UINT uMsg,
7809     UINT_PTR idEvent,
7810     DWORD dwTime
7811 )
7812 {
7813     count++;
7814 }
7815
7816 static void test_timers_no_wnd(void)
7817 {
7818     UINT_PTR id, id2;
7819     MSG msg;
7820
7821     count = 0;
7822     id = SetTimer(NULL, 0, 100, callback_count);
7823     ok(id != 0, "did not get id from SetTimer.\n");
7824     id2 = SetTimer(NULL, id, 200, callback_count);
7825     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7826     Sleep(150);
7827     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7828     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7829     Sleep(150);
7830     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7831     ok(count == 1, "did not get one count as expected (%i).\n", count);
7832     KillTimer(NULL, id);
7833     Sleep(250);
7834     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7835     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7836 }
7837
7838 /* Various win events with arbitrary parameters */
7839 static const struct message WmWinEventsSeq[] = {
7840     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7841     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7842     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7843     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7844     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7845     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7846     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7847     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7848     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7849     /* our win event hook ignores OBJID_CURSOR events */
7850     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7851     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7852     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7853     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7854     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7855     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7856     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7857     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7858     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7859     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7860     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7861     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7862     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7863     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7864     { 0 }
7865 };
7866 static const struct message WmWinEventCaretSeq[] = {
7867     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7868     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7869     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7870     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7871     { 0 }
7872 };
7873 static const struct message WmWinEventCaretSeq_2[] = {
7874     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7875     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7876     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7877     { 0 }
7878 };
7879 static const struct message WmWinEventAlertSeq[] = {
7880     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7881     { 0 }
7882 };
7883 static const struct message WmWinEventAlertSeq_2[] = {
7884     /* create window in the thread proc */
7885     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7886     /* our test event */
7887     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7888     { 0 }
7889 };
7890 static const struct message WmGlobalHookSeq_1[] = {
7891     /* create window in the thread proc */
7892     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7893     /* our test events */
7894     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7895     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7896     { 0 }
7897 };
7898 static const struct message WmGlobalHookSeq_2[] = {
7899     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7900     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7901     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7902     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7903     { 0 }
7904 };
7905
7906 static const struct message WmMouseLLHookSeq[] = {
7907     { WM_MOUSEMOVE, hook },
7908     { WM_LBUTTONUP, hook },
7909     { WM_MOUSEMOVE, hook },
7910     { 0 }
7911 };
7912
7913 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7914                                          DWORD event,
7915                                          HWND hwnd,
7916                                          LONG object_id,
7917                                          LONG child_id,
7918                                          DWORD thread_id,
7919                                          DWORD event_time)
7920 {
7921     char buf[256];
7922
7923     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7924     {
7925         if (!lstrcmpiA(buf, "TestWindowClass") ||
7926             !lstrcmpiA(buf, "static"))
7927         {
7928             struct recvd_message msg;
7929
7930             msg.hwnd = hwnd;
7931             msg.message = event;
7932             msg.flags = winevent_hook|wparam|lparam;
7933             msg.wParam = object_id;
7934             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7935             msg.descr = "WEH_2";
7936             add_message(&msg);
7937         }
7938     }
7939 }
7940
7941 static HHOOK hCBT_global_hook;
7942 static DWORD cbt_global_hook_thread_id;
7943
7944 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7945
7946     HWND hwnd;
7947     char buf[256];
7948
7949     if (nCode == HCBT_SYSCOMMAND)
7950     {
7951         struct recvd_message msg;
7952
7953         msg.hwnd = 0;
7954         msg.message = nCode;
7955         msg.flags = hook|wparam|lparam;
7956         msg.wParam = wParam;
7957         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7958         msg.descr = "CBT_2";
7959         add_message(&msg);
7960
7961         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7962     }
7963     /* WH_MOUSE_LL hook */
7964     if (nCode == HC_ACTION)
7965     {
7966         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7967
7968         /* we can't test for real mouse events */
7969         if (mhll->flags & LLMHF_INJECTED)
7970         {
7971             struct recvd_message msg;
7972
7973             memset (&msg, 0, sizeof (msg));
7974             msg.message = wParam;
7975             msg.flags = hook;
7976             msg.descr = "CBT_2";
7977             add_message(&msg);
7978         }
7979         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7980     }
7981
7982     /* Log also SetFocus(0) calls */
7983     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7984
7985     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7986     {
7987         if (!lstrcmpiA(buf, "TestWindowClass") ||
7988             !lstrcmpiA(buf, "static"))
7989         {
7990             struct recvd_message msg;
7991
7992             msg.hwnd = hwnd;
7993             msg.message = nCode;
7994             msg.flags = hook|wparam|lparam;
7995             msg.wParam = wParam;
7996             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7997             msg.descr = "CBT_2";
7998             add_message(&msg);
7999         }
8000     }
8001     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8002 }
8003
8004 static DWORD WINAPI win_event_global_thread_proc(void *param)
8005 {
8006     HWND hwnd;
8007     MSG msg;
8008     HANDLE hevent = *(HANDLE *)param;
8009
8010     assert(pNotifyWinEvent);
8011
8012     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8013     assert(hwnd);
8014     trace("created thread window %p\n", hwnd);
8015
8016     *(HWND *)param = hwnd;
8017
8018     flush_sequence();
8019     /* this event should be received only by our new hook proc,
8020      * an old one does not expect an event from another thread.
8021      */
8022     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8023     SetEvent(hevent);
8024
8025     while (GetMessage(&msg, 0, 0, 0))
8026     {
8027         TranslateMessage(&msg);
8028         DispatchMessage(&msg);
8029     }
8030     return 0;
8031 }
8032
8033 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8034 {
8035     HWND hwnd;
8036     MSG msg;
8037     HANDLE hevent = *(HANDLE *)param;
8038
8039     flush_sequence();
8040     /* these events should be received only by our new hook proc,
8041      * an old one does not expect an event from another thread.
8042      */
8043
8044     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8045     assert(hwnd);
8046     trace("created thread window %p\n", hwnd);
8047
8048     *(HWND *)param = hwnd;
8049
8050     /* Windows doesn't like when a thread plays games with the focus,
8051        that leads to all kinds of misbehaviours and failures to activate
8052        a window. So, better keep next lines commented out.
8053     SetFocus(0);
8054     SetFocus(hwnd);*/
8055
8056     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8057     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8058
8059     SetEvent(hevent);
8060
8061     while (GetMessage(&msg, 0, 0, 0))
8062     {
8063         TranslateMessage(&msg);
8064         DispatchMessage(&msg);
8065     }
8066     return 0;
8067 }
8068
8069 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8070 {
8071     HWND hwnd;
8072     MSG msg;
8073     HANDLE hevent = *(HANDLE *)param;
8074
8075     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8076     assert(hwnd);
8077     trace("created thread window %p\n", hwnd);
8078
8079     *(HWND *)param = hwnd;
8080
8081     flush_sequence();
8082
8083     /* Windows doesn't like when a thread plays games with the focus,
8084      * that leads to all kinds of misbehaviours and failures to activate
8085      * a window. So, better don't generate a mouse click message below.
8086      */
8087     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8088     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8089     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8090
8091     SetEvent(hevent);
8092     while (GetMessage(&msg, 0, 0, 0))
8093     {
8094         TranslateMessage(&msg);
8095         DispatchMessage(&msg);
8096     }
8097     return 0;
8098 }
8099
8100 static void test_winevents(void)
8101 {
8102     BOOL ret;
8103     MSG msg;
8104     HWND hwnd, hwnd2;
8105     UINT i;
8106     HANDLE hthread, hevent;
8107     DWORD tid;
8108     HWINEVENTHOOK hhook;
8109     const struct message *events = WmWinEventsSeq;
8110
8111     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8112                            WS_OVERLAPPEDWINDOW,
8113                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8114                            NULL, NULL, 0);
8115     assert(hwnd);
8116
8117     /****** start of global hook test *************/
8118     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8119     if (!hCBT_global_hook)
8120     {
8121         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8122         skip( "cannot set global hook\n" );
8123         return;
8124     }
8125
8126     hevent = CreateEventA(NULL, 0, 0, NULL);
8127     assert(hevent);
8128     hwnd2 = hevent;
8129
8130     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8131     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8132
8133     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8134
8135     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8136
8137     flush_sequence();
8138     /* this one should be received only by old hook proc */
8139     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8140     /* this one should be received only by old hook proc */
8141     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8142
8143     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8144
8145     ret = UnhookWindowsHookEx(hCBT_global_hook);
8146     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8147
8148     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8149     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8150     CloseHandle(hthread);
8151     CloseHandle(hevent);
8152     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8153     /****** end of global hook test *************/
8154
8155     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8156     {
8157         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8158         return;
8159     }
8160
8161     flush_sequence();
8162
8163     if (0)
8164     {
8165     /* this test doesn't pass under Win9x */
8166     /* win2k ignores events with hwnd == 0 */
8167     SetLastError(0xdeadbeef);
8168     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8169     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8170        GetLastError() == 0xdeadbeef, /* Win9x */
8171        "unexpected error %d\n", GetLastError());
8172     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8173     }
8174
8175     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8176         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8177
8178     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8179
8180     /****** start of event filtering test *************/
8181     hhook = pSetWinEventHook(
8182         EVENT_OBJECT_SHOW, /* 0x8002 */
8183         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8184         GetModuleHandleA(0), win_event_global_hook_proc,
8185         GetCurrentProcessId(), 0,
8186         WINEVENT_INCONTEXT);
8187     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8188
8189     hevent = CreateEventA(NULL, 0, 0, NULL);
8190     assert(hevent);
8191     hwnd2 = hevent;
8192
8193     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8194     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8195
8196     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8197
8198     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8199
8200     flush_sequence();
8201     /* this one should be received only by old hook proc */
8202     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8203     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8204     /* this one should be received only by old hook proc */
8205     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8206
8207     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8208
8209     ret = pUnhookWinEvent(hhook);
8210     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8211
8212     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8213     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8214     CloseHandle(hthread);
8215     CloseHandle(hevent);
8216     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8217     /****** end of event filtering test *************/
8218
8219     /****** start of out of context event test *************/
8220     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8221         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8222         WINEVENT_OUTOFCONTEXT);
8223     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8224
8225     hevent = CreateEventA(NULL, 0, 0, NULL);
8226     assert(hevent);
8227     hwnd2 = hevent;
8228
8229     flush_sequence();
8230
8231     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8232     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8233
8234     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8235
8236     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8237     /* process pending winevent messages */
8238     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8239     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8240
8241     flush_sequence();
8242     /* this one should be received only by old hook proc */
8243     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8244     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8245     /* this one should be received only by old hook proc */
8246     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8247
8248     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8249     /* process pending winevent messages */
8250     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8251     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8252
8253     ret = pUnhookWinEvent(hhook);
8254     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8255
8256     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8257     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8258     CloseHandle(hthread);
8259     CloseHandle(hevent);
8260     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8261     /****** end of out of context event test *************/
8262
8263     /****** start of MOUSE_LL hook test *************/
8264     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8265     /* WH_MOUSE_LL is not supported on Win9x platforms */
8266     if (!hCBT_global_hook)
8267     {
8268         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8269         goto skip_mouse_ll_hook_test;
8270     }
8271
8272     hevent = CreateEventA(NULL, 0, 0, NULL);
8273     assert(hevent);
8274     hwnd2 = hevent;
8275
8276     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8277     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8278
8279     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8280         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8281
8282     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8283     flush_sequence();
8284
8285     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8286     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8287     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8288
8289     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8290
8291     ret = UnhookWindowsHookEx(hCBT_global_hook);
8292     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8293
8294     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8295     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8296     CloseHandle(hthread);
8297     CloseHandle(hevent);
8298     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8299     /****** end of MOUSE_LL hook test *************/
8300 skip_mouse_ll_hook_test:
8301
8302     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8303 }
8304
8305 static void test_set_hook(void)
8306 {
8307     BOOL ret;
8308     HHOOK hhook;
8309     HWINEVENTHOOK hwinevent_hook;
8310
8311     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8312     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8313     UnhookWindowsHookEx(hhook);
8314
8315     if (0)
8316     {
8317     /* this test doesn't pass under Win9x: BUG! */
8318     SetLastError(0xdeadbeef);
8319     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8320     ok(!hhook, "global hook requires hModule != 0\n");
8321     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8322     }
8323
8324     SetLastError(0xdeadbeef);
8325     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8326     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8327     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8328        GetLastError() == 0xdeadbeef, /* Win9x */
8329        "unexpected error %d\n", GetLastError());
8330
8331     SetLastError(0xdeadbeef);
8332     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8333     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8334        GetLastError() == 0xdeadbeef, /* Win9x */
8335        "unexpected error %d\n", GetLastError());
8336
8337     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8338
8339     /* even process local incontext hooks require hmodule */
8340     SetLastError(0xdeadbeef);
8341     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8342         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8343     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8344     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8345        GetLastError() == 0xdeadbeef, /* Win9x */
8346        "unexpected error %d\n", GetLastError());
8347
8348     /* even thread local incontext hooks require hmodule */
8349     SetLastError(0xdeadbeef);
8350     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8351         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8352     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8353     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8354        GetLastError() == 0xdeadbeef, /* Win9x */
8355        "unexpected error %d\n", GetLastError());
8356
8357     if (0)
8358     {
8359     /* these 3 tests don't pass under Win9x */
8360     SetLastError(0xdeadbeef);
8361     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8362         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8363     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8364     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8365
8366     SetLastError(0xdeadbeef);
8367     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8368         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8369     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8370     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8371
8372     SetLastError(0xdeadbeef);
8373     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8374         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8375     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8376     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8377     }
8378
8379     SetLastError(0xdeadbeef);
8380     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8381         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8382     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8383     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8384     ret = pUnhookWinEvent(hwinevent_hook);
8385     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8386
8387 todo_wine {
8388     /* This call succeeds under win2k SP4, but fails under Wine.
8389        Does win2k test/use passed process id? */
8390     SetLastError(0xdeadbeef);
8391     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8392         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8393     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8394     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8395     ret = pUnhookWinEvent(hwinevent_hook);
8396     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8397 }
8398
8399     SetLastError(0xdeadbeef);
8400     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8401     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8402         GetLastError() == 0xdeadbeef, /* Win9x */
8403         "unexpected error %d\n", GetLastError());
8404 }
8405
8406 static const struct message ScrollWindowPaint1[] = {
8407     { WM_PAINT, sent },
8408     { WM_ERASEBKGND, sent|beginpaint },
8409     { WM_GETTEXTLENGTH, sent|optional },
8410     { WM_PAINT, sent|optional },
8411     { WM_NCPAINT, sent|beginpaint|optional },
8412     { WM_GETTEXT, sent|beginpaint|optional },
8413     { WM_GETTEXT, sent|beginpaint|optional },
8414     { WM_GETTEXT, sent|beginpaint|optional },
8415     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8416     { WM_ERASEBKGND, sent|beginpaint|optional },
8417     { 0 }
8418 };
8419
8420 static const struct message ScrollWindowPaint2[] = {
8421     { WM_PAINT, sent },
8422     { 0 }
8423 };
8424
8425 static void test_scrollwindowex(void)
8426 {
8427     HWND hwnd, hchild;
8428     RECT rect={0,0,130,130};
8429
8430     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8431             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8432             100, 100, 200, 200, 0, 0, 0, NULL);
8433     ok (hwnd != 0, "Failed to create overlapped window\n");
8434     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8435             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8436             10, 10, 150, 150, hwnd, 0, 0, NULL);
8437     ok (hchild != 0, "Failed to create child\n");
8438     UpdateWindow(hwnd);
8439     flush_events();
8440     flush_sequence();
8441
8442     /* scroll without the child window */
8443     trace("start scroll\n");
8444     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8445             SW_ERASE|SW_INVALIDATE);
8446     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8447     trace("end scroll\n");
8448     flush_sequence();
8449     flush_events();
8450     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8451     flush_events();
8452     flush_sequence();
8453
8454     /* Now without the SW_ERASE flag */
8455     trace("start scroll\n");
8456     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8457     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8458     trace("end scroll\n");
8459     flush_sequence();
8460     flush_events();
8461     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8462     flush_events();
8463     flush_sequence();
8464
8465     /* now scroll the child window as well */
8466     trace("start scroll\n");
8467     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8468             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8469     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8470     /* windows sometimes a WM_MOVE */
8471     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8472     trace("end scroll\n");
8473     flush_sequence();
8474     flush_events();
8475     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8476     flush_events();
8477     flush_sequence();
8478
8479     /* now scroll with ScrollWindow() */
8480     trace("start scroll with ScrollWindow\n");
8481     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8482     trace("end scroll\n");
8483     flush_sequence();
8484     flush_events();
8485     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8486
8487     ok(DestroyWindow(hchild), "failed to destroy window\n");
8488     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8489     flush_sequence();
8490 }
8491
8492 static const struct message destroy_window_with_children[] = {
8493     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8494     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8495     { 0x0090, sent|optional },
8496     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8497     { 0x0090, sent|optional },
8498     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8499     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8500     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8501     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8502     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8503     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8504     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8505     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8506     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8507     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8508     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8509     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8510     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8511     { 0 }
8512 };
8513
8514 static void test_DestroyWindow(void)
8515 {
8516     BOOL ret;
8517     HWND parent, child1, child2, child3, child4, test;
8518     UINT_PTR child_id = WND_CHILD_ID + 1;
8519
8520     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8521                              100, 100, 200, 200, 0, 0, 0, NULL);
8522     assert(parent != 0);
8523     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8524                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8525     assert(child1 != 0);
8526     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8527                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8528     assert(child2 != 0);
8529     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8530                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8531     assert(child3 != 0);
8532     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8533                              0, 0, 50, 50, parent, 0, 0, NULL);
8534     assert(child4 != 0);
8535
8536     /* test owner/parent of child2 */
8537     test = GetParent(child2);
8538     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8539     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8540     if(pGetAncestor) {
8541         test = pGetAncestor(child2, GA_PARENT);
8542         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8543     }
8544     test = GetWindow(child2, GW_OWNER);
8545     ok(!test, "wrong owner %p\n", test);
8546
8547     test = SetParent(child2, parent);
8548     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8549
8550     /* test owner/parent of the parent */
8551     test = GetParent(parent);
8552     ok(!test, "wrong parent %p\n", test);
8553     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8554     if(pGetAncestor) {
8555         test = pGetAncestor(parent, GA_PARENT);
8556         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8557     }
8558     test = GetWindow(parent, GW_OWNER);
8559     ok(!test, "wrong owner %p\n", test);
8560
8561     /* test owner/parent of child1 */
8562     test = GetParent(child1);
8563     ok(test == parent, "wrong parent %p\n", test);
8564     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8565     if(pGetAncestor) {
8566         test = pGetAncestor(child1, GA_PARENT);
8567         ok(test == parent, "wrong parent %p\n", test);
8568     }
8569     test = GetWindow(child1, GW_OWNER);
8570     ok(!test, "wrong owner %p\n", test);
8571
8572     /* test owner/parent of child2 */
8573     test = GetParent(child2);
8574     ok(test == parent, "wrong parent %p\n", test);
8575     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8576     if(pGetAncestor) {
8577         test = pGetAncestor(child2, GA_PARENT);
8578         ok(test == parent, "wrong parent %p\n", test);
8579     }
8580     test = GetWindow(child2, GW_OWNER);
8581     ok(!test, "wrong owner %p\n", test);
8582
8583     /* test owner/parent of child3 */
8584     test = GetParent(child3);
8585     ok(test == child1, "wrong parent %p\n", test);
8586     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8587     if(pGetAncestor) {
8588         test = pGetAncestor(child3, GA_PARENT);
8589         ok(test == child1, "wrong parent %p\n", test);
8590     }
8591     test = GetWindow(child3, GW_OWNER);
8592     ok(!test, "wrong owner %p\n", test);
8593
8594     /* test owner/parent of child4 */
8595     test = GetParent(child4);
8596     ok(test == parent, "wrong parent %p\n", test);
8597     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8598     if(pGetAncestor) {
8599         test = pGetAncestor(child4, GA_PARENT);
8600         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8601     }
8602     test = GetWindow(child4, GW_OWNER);
8603     ok(test == parent, "wrong owner %p\n", test);
8604
8605     flush_sequence();
8606
8607     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8608            parent, child1, child2, child3, child4);
8609
8610     SetCapture(child4);
8611     test = GetCapture();
8612     ok(test == child4, "wrong capture window %p\n", test);
8613
8614     test_DestroyWindow_flag = TRUE;
8615     ret = DestroyWindow(parent);
8616     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8617     test_DestroyWindow_flag = FALSE;
8618     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8619
8620     ok(!IsWindow(parent), "parent still exists\n");
8621     ok(!IsWindow(child1), "child1 still exists\n");
8622     ok(!IsWindow(child2), "child2 still exists\n");
8623     ok(!IsWindow(child3), "child3 still exists\n");
8624     ok(!IsWindow(child4), "child4 still exists\n");
8625
8626     test = GetCapture();
8627     ok(!test, "wrong capture window %p\n", test);
8628 }
8629
8630
8631 static const struct message WmDispatchPaint[] = {
8632     { WM_NCPAINT, sent },
8633     { WM_GETTEXT, sent|defwinproc|optional },
8634     { WM_GETTEXT, sent|defwinproc|optional },
8635     { WM_ERASEBKGND, sent },
8636     { 0 }
8637 };
8638
8639 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8640 {
8641     if (message == WM_PAINT) return 0;
8642     return MsgCheckProcA( hwnd, message, wParam, lParam );
8643 }
8644
8645 static void test_DispatchMessage(void)
8646 {
8647     RECT rect;
8648     MSG msg;
8649     int count;
8650     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8651                                100, 100, 200, 200, 0, 0, 0, NULL);
8652     ShowWindow( hwnd, SW_SHOW );
8653     UpdateWindow( hwnd );
8654     flush_events();
8655     flush_sequence();
8656     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8657
8658     SetRect( &rect, -5, -5, 5, 5 );
8659     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8660     count = 0;
8661     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8662     {
8663         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8664         else
8665         {
8666             flush_sequence();
8667             DispatchMessage( &msg );
8668             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8669             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8670             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8671             if (++count > 10) break;
8672         }
8673     }
8674     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8675
8676     trace("now without DispatchMessage\n");
8677     flush_sequence();
8678     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8679     count = 0;
8680     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8681     {
8682         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8683         else
8684         {
8685             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8686             flush_sequence();
8687             /* this will send WM_NCCPAINT just like DispatchMessage does */
8688             GetUpdateRgn( hwnd, hrgn, TRUE );
8689             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8690             DeleteObject( hrgn );
8691             GetClientRect( hwnd, &rect );
8692             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8693             ok( !count, "Got multiple WM_PAINTs\n" );
8694             if (++count > 10) break;
8695         }
8696     }
8697     DestroyWindow(hwnd);
8698 }
8699
8700
8701 static const struct message WmUser[] = {
8702     { WM_USER, sent },
8703     { 0 }
8704 };
8705
8706 struct sendmsg_info
8707 {
8708     HWND  hwnd;
8709     DWORD timeout;
8710     DWORD ret;
8711 };
8712
8713 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8714 {
8715     struct sendmsg_info *info = arg;
8716     SetLastError( 0xdeadbeef );
8717     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8718     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8719                         broken(GetLastError() == 0),  /* win9x */
8720                         "unexpected error %d\n", GetLastError());
8721     return 0;
8722 }
8723
8724 static void wait_for_thread( HANDLE thread )
8725 {
8726     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8727     {
8728         MSG msg;
8729         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8730     }
8731 }
8732
8733 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8734 {
8735     if (message == WM_USER) Sleep(200);
8736     return MsgCheckProcA( hwnd, message, wParam, lParam );
8737 }
8738
8739 static void test_SendMessageTimeout(void)
8740 {
8741     HANDLE thread;
8742     struct sendmsg_info info;
8743     DWORD tid;
8744     BOOL is_win9x;
8745
8746     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8747                                100, 100, 200, 200, 0, 0, 0, NULL);
8748     flush_events();
8749     flush_sequence();
8750
8751     info.timeout = 1000;
8752     info.ret = 0xdeadbeef;
8753     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8754     wait_for_thread( thread );
8755     CloseHandle( thread );
8756     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8757     ok_sequence( WmUser, "WmUser", FALSE );
8758
8759     info.timeout = 1;
8760     info.ret = 0xdeadbeef;
8761     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8762     Sleep(100);  /* SendMessageTimeout should time out here */
8763     wait_for_thread( thread );
8764     CloseHandle( thread );
8765     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8766     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8767
8768     /* 0 means infinite timeout (but not on win9x) */
8769     info.timeout = 0;
8770     info.ret = 0xdeadbeef;
8771     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8772     Sleep(100);
8773     wait_for_thread( thread );
8774     CloseHandle( thread );
8775     is_win9x = !info.ret;
8776     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8777     else ok_sequence( WmUser, "WmUser", FALSE );
8778
8779     /* timeout is treated as signed despite the prototype (but not on win9x) */
8780     info.timeout = 0x7fffffff;
8781     info.ret = 0xdeadbeef;
8782     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8783     Sleep(100);
8784     wait_for_thread( thread );
8785     CloseHandle( thread );
8786     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8787     ok_sequence( WmUser, "WmUser", FALSE );
8788
8789     info.timeout = 0x80000000;
8790     info.ret = 0xdeadbeef;
8791     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8792     Sleep(100);
8793     wait_for_thread( thread );
8794     CloseHandle( thread );
8795     if (is_win9x)
8796     {
8797         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8798         ok_sequence( WmUser, "WmUser", FALSE );
8799     }
8800     else
8801     {
8802         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8803         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8804     }
8805
8806     /* now check for timeout during message processing */
8807     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8808     info.timeout = 100;
8809     info.ret = 0xdeadbeef;
8810     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8811     wait_for_thread( thread );
8812     CloseHandle( thread );
8813     /* we should time out but still get the message */
8814     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8815     ok_sequence( WmUser, "WmUser", FALSE );
8816
8817     DestroyWindow( info.hwnd );
8818 }
8819
8820
8821 /****************** edit message test *************************/
8822 #define ID_EDIT 0x1234
8823 static const struct message sl_edit_setfocus[] =
8824 {
8825     { HCBT_SETFOCUS, hook },
8826     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8827     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8828     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8829     { WM_SETFOCUS, sent|wparam, 0 },
8830     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8831     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8832     { WM_CTLCOLOREDIT, sent|parent },
8833     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8834     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8835     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8836     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8837     { 0 }
8838 };
8839 static const struct message ml_edit_setfocus[] =
8840 {
8841     { HCBT_SETFOCUS, hook },
8842     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8843     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8844     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8845     { WM_SETFOCUS, sent|wparam, 0 },
8846     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8847     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8848     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8849     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8850     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8851     { 0 }
8852 };
8853 static const struct message sl_edit_killfocus[] =
8854 {
8855     { HCBT_SETFOCUS, hook },
8856     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8857     { WM_KILLFOCUS, sent|wparam, 0 },
8858     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8859     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8860     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8861     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8862     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8863     { 0 }
8864 };
8865 static const struct message sl_edit_lbutton_dblclk[] =
8866 {
8867     { WM_LBUTTONDBLCLK, sent },
8868     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8869     { 0 }
8870 };
8871 static const struct message sl_edit_lbutton_down[] =
8872 {
8873     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8874     { HCBT_SETFOCUS, hook },
8875     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8876     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8877     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8878     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8879     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8880     { WM_CTLCOLOREDIT, sent|parent },
8881     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8882     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8883     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8884     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8885     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8886     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8887     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8888     { WM_CTLCOLOREDIT, sent|parent|optional },
8889     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8890     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8891     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8892     { 0 }
8893 };
8894 static const struct message ml_edit_lbutton_down[] =
8895 {
8896     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8897     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8898     { HCBT_SETFOCUS, hook },
8899     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8900     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8901     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8902     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8903     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8904     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8905     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8906     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8907     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8908     { 0 }
8909 };
8910 static const struct message sl_edit_lbutton_up[] =
8911 {
8912     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8913     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8914     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8915     { WM_CAPTURECHANGED, sent|defwinproc },
8916     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8917     { 0 }
8918 };
8919 static const struct message ml_edit_lbutton_up[] =
8920 {
8921     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8922     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8923     { WM_CAPTURECHANGED, sent|defwinproc },
8924     { 0 }
8925 };
8926
8927 static WNDPROC old_edit_proc;
8928
8929 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8930 {
8931     static long defwndproc_counter = 0;
8932     LRESULT ret;
8933     struct recvd_message msg;
8934
8935     if (ignore_message( message )) return 0;
8936
8937     msg.hwnd = hwnd;
8938     msg.message = message;
8939     msg.flags = sent|wparam|lparam;
8940     if (defwndproc_counter) msg.flags |= defwinproc;
8941     msg.wParam = wParam;
8942     msg.lParam = lParam;
8943     msg.descr = "edit";
8944     add_message(&msg);
8945
8946     defwndproc_counter++;
8947     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8948     defwndproc_counter--;
8949
8950     return ret;
8951 }
8952
8953 static void subclass_edit(void)
8954 {
8955     WNDCLASSA cls;
8956
8957     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8958
8959     old_edit_proc = cls.lpfnWndProc;
8960
8961     cls.hInstance = GetModuleHandle(0);
8962     cls.lpfnWndProc = edit_hook_proc;
8963     cls.lpszClassName = "my_edit_class";
8964     UnregisterClass(cls.lpszClassName, cls.hInstance);
8965     if (!RegisterClassA(&cls)) assert(0);
8966 }
8967
8968 static void test_edit_messages(void)
8969 {
8970     HWND hwnd, parent;
8971     DWORD dlg_code;
8972
8973     subclass_edit();
8974     log_all_parent_messages++;
8975
8976     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8977                              100, 100, 200, 200, 0, 0, 0, NULL);
8978     ok (parent != 0, "Failed to create parent window\n");
8979
8980     /* test single line edit */
8981     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8982                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8983     ok(hwnd != 0, "Failed to create edit window\n");
8984
8985     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8986     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8987
8988     ShowWindow(hwnd, SW_SHOW);
8989     UpdateWindow(hwnd);
8990     SetFocus(0);
8991     flush_sequence();
8992
8993     SetFocus(hwnd);
8994     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8995
8996     SetFocus(0);
8997     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8998
8999     SetFocus(0);
9000     ReleaseCapture();
9001     flush_sequence();
9002
9003     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9004     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9005
9006     SetFocus(0);
9007     ReleaseCapture();
9008     flush_sequence();
9009
9010     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9011     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9012
9013     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9014     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9015
9016     DestroyWindow(hwnd);
9017
9018     /* test multiline edit */
9019     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9020                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9021     ok(hwnd != 0, "Failed to create edit window\n");
9022
9023     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9024     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9025        "wrong dlg_code %08x\n", dlg_code);
9026
9027     ShowWindow(hwnd, SW_SHOW);
9028     UpdateWindow(hwnd);
9029     SetFocus(0);
9030     flush_sequence();
9031
9032     SetFocus(hwnd);
9033     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9034
9035     SetFocus(0);
9036     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9037
9038     SetFocus(0);
9039     ReleaseCapture();
9040     flush_sequence();
9041
9042     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9043     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9044
9045     SetFocus(0);
9046     ReleaseCapture();
9047     flush_sequence();
9048
9049     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9050     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9051
9052     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9053     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9054
9055     DestroyWindow(hwnd);
9056     DestroyWindow(parent);
9057
9058     log_all_parent_messages--;
9059 }
9060
9061 /**************************** End of Edit test ******************************/
9062
9063 static const struct message WmKeyDownSkippedSeq[] =
9064 {
9065     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9066     { 0 }
9067 };
9068 static const struct message WmKeyDownWasDownSkippedSeq[] =
9069 {
9070     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9071     { 0 }
9072 };
9073 static const struct message WmKeyUpSkippedSeq[] =
9074 {
9075     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9076     { 0 }
9077 };
9078 static const struct message WmUserKeyUpSkippedSeq[] =
9079 {
9080     { WM_USER, sent },
9081     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9082     { 0 }
9083 };
9084
9085 #define EV_STOP 0
9086 #define EV_SENDMSG 1
9087 #define EV_ACK 2
9088
9089 struct peekmsg_info
9090 {
9091     HWND  hwnd;
9092     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9093 };
9094
9095 static DWORD CALLBACK send_msg_thread_2(void *param)
9096 {
9097     DWORD ret;
9098     struct peekmsg_info *info = param;
9099
9100     trace("thread: looping\n");
9101     SetEvent(info->hevent[EV_ACK]);
9102
9103     while (1)
9104     {
9105         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9106
9107         switch (ret)
9108         {
9109         case WAIT_OBJECT_0 + EV_STOP:
9110             trace("thread: exiting\n");
9111             return 0;
9112
9113         case WAIT_OBJECT_0 + EV_SENDMSG:
9114             trace("thread: sending message\n");
9115             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
9116                 "SendNotifyMessageA failed error %u\n", GetLastError());
9117             SetEvent(info->hevent[EV_ACK]);
9118             break;
9119
9120         default:
9121             trace("unexpected return: %04x\n", ret);
9122             assert(0);
9123             break;
9124         }
9125     }
9126     return 0;
9127 }
9128
9129 static void test_PeekMessage(void)
9130 {
9131     MSG msg;
9132     HANDLE hthread;
9133     DWORD tid, qstatus;
9134     UINT qs_all_input = QS_ALLINPUT;
9135     UINT qs_input = QS_INPUT;
9136     BOOL ret;
9137     struct peekmsg_info info;
9138
9139     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9140                               100, 100, 200, 200, 0, 0, 0, NULL);
9141     assert(info.hwnd);
9142     ShowWindow(info.hwnd, SW_SHOW);
9143     UpdateWindow(info.hwnd);
9144     SetFocus(info.hwnd);
9145
9146     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9147     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9148     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9149
9150     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9151     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9152
9153     flush_events();
9154     flush_sequence();
9155
9156     SetLastError(0xdeadbeef);
9157     qstatus = GetQueueStatus(qs_all_input);
9158     if (GetLastError() == ERROR_INVALID_FLAGS)
9159     {
9160         trace("QS_RAWINPUT not supported on this platform\n");
9161         qs_all_input &= ~QS_RAWINPUT;
9162         qs_input &= ~QS_RAWINPUT;
9163     }
9164     if (qstatus & QS_POSTMESSAGE)
9165     {
9166         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9167         qstatus = GetQueueStatus(qs_all_input);
9168     }
9169     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9170
9171     trace("signalling to send message\n");
9172     SetEvent(info.hevent[EV_SENDMSG]);
9173     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9174
9175     /* pass invalid QS_xxxx flags */
9176     SetLastError(0xdeadbeef);
9177     qstatus = GetQueueStatus(0xffffffff);
9178     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9179     if (!qstatus)
9180     {
9181         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9182         qstatus = GetQueueStatus(qs_all_input);
9183     }
9184     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9185     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9186        "wrong qstatus %08x\n", qstatus);
9187
9188     msg.message = 0;
9189     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9190     ok(!ret,
9191        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9192         msg.message);
9193     ok_sequence(WmUser, "WmUser", FALSE);
9194
9195     qstatus = GetQueueStatus(qs_all_input);
9196     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9197
9198     keybd_event('N', 0, 0, 0);
9199     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9200     qstatus = GetQueueStatus(qs_all_input);
9201     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9202     {
9203         skip( "queuing key events not supported\n" );
9204         goto done;
9205     }
9206     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
9207        "wrong qstatus %08x\n", qstatus);
9208
9209     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9210     qstatus = GetQueueStatus(qs_all_input);
9211     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9212        "wrong qstatus %08x\n", qstatus);
9213
9214     InvalidateRect(info.hwnd, NULL, FALSE);
9215     qstatus = GetQueueStatus(qs_all_input);
9216     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9217        "wrong qstatus %08x\n", qstatus);
9218
9219     trace("signalling to send message\n");
9220     SetEvent(info.hevent[EV_SENDMSG]);
9221     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9222
9223     qstatus = GetQueueStatus(qs_all_input);
9224     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9225        "wrong qstatus %08x\n", qstatus);
9226
9227     msg.message = 0;
9228     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9229     if (ret && msg.message == WM_CHAR)
9230     {
9231         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9232         goto done;
9233     }
9234     ok(!ret,
9235        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9236         msg.message);
9237     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9238     {
9239         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9240         goto done;
9241     }
9242     ok_sequence(WmUser, "WmUser", FALSE);
9243
9244     qstatus = GetQueueStatus(qs_all_input);
9245     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9246        "wrong qstatus %08x\n", qstatus);
9247
9248     trace("signalling to send message\n");
9249     SetEvent(info.hevent[EV_SENDMSG]);
9250     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9251
9252     qstatus = GetQueueStatus(qs_all_input);
9253     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9254        "wrong qstatus %08x\n", qstatus);
9255
9256     msg.message = 0;
9257     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9258     ok(!ret,
9259        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9260         msg.message);
9261     ok_sequence(WmUser, "WmUser", FALSE);
9262
9263     qstatus = GetQueueStatus(qs_all_input);
9264     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9265        "wrong qstatus %08x\n", qstatus);
9266
9267     msg.message = 0;
9268     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9269     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9270        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9271        ret, msg.message, msg.wParam);
9272     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9273
9274     qstatus = GetQueueStatus(qs_all_input);
9275     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9276        "wrong qstatus %08x\n", qstatus);
9277
9278     msg.message = 0;
9279     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9280     ok(!ret,
9281        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9282         msg.message);
9283     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9284
9285     qstatus = GetQueueStatus(qs_all_input);
9286     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9287        "wrong qstatus %08x\n", qstatus);
9288
9289     msg.message = 0;
9290     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9291     ok(ret && msg.message == WM_PAINT,
9292        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9293     DispatchMessageA(&msg);
9294     ok_sequence(WmPaint, "WmPaint", FALSE);
9295
9296     qstatus = GetQueueStatus(qs_all_input);
9297     ok(qstatus == MAKELONG(0, QS_KEY),
9298        "wrong qstatus %08x\n", qstatus);
9299
9300     msg.message = 0;
9301     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9302     ok(!ret,
9303        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9304         msg.message);
9305     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9306
9307     qstatus = GetQueueStatus(qs_all_input);
9308     ok(qstatus == MAKELONG(0, QS_KEY),
9309        "wrong qstatus %08x\n", qstatus);
9310
9311     trace("signalling to send message\n");
9312     SetEvent(info.hevent[EV_SENDMSG]);
9313     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9314
9315     qstatus = GetQueueStatus(qs_all_input);
9316     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9317        "wrong qstatus %08x\n", qstatus);
9318
9319     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9320
9321     qstatus = GetQueueStatus(qs_all_input);
9322     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9323        "wrong qstatus %08x\n", qstatus);
9324
9325     msg.message = 0;
9326     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9327     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9328        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9329        ret, msg.message, msg.wParam);
9330     ok_sequence(WmUser, "WmUser", FALSE);
9331
9332     qstatus = GetQueueStatus(qs_all_input);
9333     ok(qstatus == MAKELONG(0, QS_KEY),
9334        "wrong qstatus %08x\n", qstatus);
9335
9336     msg.message = 0;
9337     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9338     ok(!ret,
9339        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9340         msg.message);
9341     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9342
9343     qstatus = GetQueueStatus(qs_all_input);
9344     ok(qstatus == MAKELONG(0, QS_KEY),
9345        "wrong qstatus %08x\n", qstatus);
9346
9347     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9348
9349     qstatus = GetQueueStatus(qs_all_input);
9350     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9351        "wrong qstatus %08x\n", qstatus);
9352
9353     trace("signalling to send message\n");
9354     SetEvent(info.hevent[EV_SENDMSG]);
9355     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9356
9357     qstatus = GetQueueStatus(qs_all_input);
9358     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9359        "wrong qstatus %08x\n", qstatus);
9360
9361     msg.message = 0;
9362     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9363     ok(!ret,
9364        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9365         msg.message);
9366     ok_sequence(WmUser, "WmUser", FALSE);
9367
9368     qstatus = GetQueueStatus(qs_all_input);
9369     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9370        "wrong qstatus %08x\n", qstatus);
9371
9372     msg.message = 0;
9373     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9374         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9375     else /* workaround for a missing QS_RAWINPUT support */
9376         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9377     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9378        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9379        ret, msg.message, msg.wParam);
9380     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9381
9382     qstatus = GetQueueStatus(qs_all_input);
9383     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9384        "wrong qstatus %08x\n", qstatus);
9385
9386     msg.message = 0;
9387     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9388         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9389     else /* workaround for a missing QS_RAWINPUT support */
9390         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9391     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9392        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9393        ret, msg.message, msg.wParam);
9394     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9395
9396     qstatus = GetQueueStatus(qs_all_input);
9397     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9398        "wrong qstatus %08x\n", qstatus);
9399
9400     msg.message = 0;
9401     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9402     ok(!ret,
9403        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9404         msg.message);
9405     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9406
9407     qstatus = GetQueueStatus(qs_all_input);
9408     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9409        "wrong qstatus %08x\n", qstatus);
9410
9411     msg.message = 0;
9412     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9413     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9414        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9415        ret, msg.message, msg.wParam);
9416     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9417
9418     qstatus = GetQueueStatus(qs_all_input);
9419     ok(qstatus == 0,
9420        "wrong qstatus %08x\n", qstatus);
9421
9422     msg.message = 0;
9423     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9424     ok(!ret,
9425        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9426         msg.message);
9427     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9428
9429     qstatus = GetQueueStatus(qs_all_input);
9430     ok(qstatus == 0,
9431        "wrong qstatus %08x\n", qstatus);
9432
9433     /* test whether presence of the quit flag in the queue affects
9434      * the queue state
9435      */
9436     PostQuitMessage(0x1234abcd);
9437
9438     qstatus = GetQueueStatus(qs_all_input);
9439     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9440        "wrong qstatus %08x\n", qstatus);
9441
9442     PostMessageA(info.hwnd, WM_USER, 0, 0);
9443
9444     qstatus = GetQueueStatus(qs_all_input);
9445     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9446        "wrong qstatus %08x\n", qstatus);
9447
9448     msg.message = 0;
9449     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9450     ok(ret && msg.message == WM_USER,
9451        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9452     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9453
9454     qstatus = GetQueueStatus(qs_all_input);
9455     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9456        "wrong qstatus %08x\n", qstatus);
9457
9458     msg.message = 0;
9459     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9460     ok(ret && msg.message == WM_QUIT,
9461        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9462     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9463     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9464     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9465
9466     qstatus = GetQueueStatus(qs_all_input);
9467 todo_wine {
9468     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9469        "wrong qstatus %08x\n", qstatus);
9470 }
9471
9472     msg.message = 0;
9473     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9474     ok(!ret,
9475        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9476         msg.message);
9477     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9478
9479     qstatus = GetQueueStatus(qs_all_input);
9480     ok(qstatus == 0,
9481        "wrong qstatus %08x\n", qstatus);
9482
9483     /* some GetMessage tests */
9484
9485     keybd_event('N', 0, 0, 0);
9486     qstatus = GetQueueStatus(qs_all_input);
9487     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9488
9489     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9490     qstatus = GetQueueStatus(qs_all_input);
9491     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9492
9493     if (qstatus)
9494     {
9495         ret = GetMessageA( &msg, 0, 0, 0 );
9496         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9497            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9498            ret, msg.message, msg.wParam);
9499         qstatus = GetQueueStatus(qs_all_input);
9500         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9501     }
9502
9503     if (qstatus)
9504     {
9505         ret = GetMessageA( &msg, 0, 0, 0 );
9506         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9507            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9508            ret, msg.message, msg.wParam);
9509         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9510         qstatus = GetQueueStatus(qs_all_input);
9511         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9512     }
9513
9514     keybd_event('N', 0, 0, 0);
9515     qstatus = GetQueueStatus(qs_all_input);
9516     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9517
9518     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9519     qstatus = GetQueueStatus(qs_all_input);
9520     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9521
9522     if (qstatus & (QS_KEY << 16))
9523     {
9524         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9525         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9526            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9527            ret, msg.message, msg.wParam);
9528         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9529         qstatus = GetQueueStatus(qs_all_input);
9530         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9531     }
9532
9533     if (qstatus)
9534     {
9535         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9536         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9537            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9538            ret, msg.message, msg.wParam);
9539         qstatus = GetQueueStatus(qs_all_input);
9540         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9541     }
9542
9543     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9544     qstatus = GetQueueStatus(qs_all_input);
9545     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9546
9547     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9548     qstatus = GetQueueStatus(qs_all_input);
9549     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9550
9551     trace("signalling to send message\n");
9552     SetEvent(info.hevent[EV_SENDMSG]);
9553     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9554     qstatus = GetQueueStatus(qs_all_input);
9555     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9556        "wrong qstatus %08x\n", qstatus);
9557
9558     if (qstatus & (QS_KEY << 16))
9559     {
9560         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9561         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9562            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9563            ret, msg.message, msg.wParam);
9564         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9565         qstatus = GetQueueStatus(qs_all_input);
9566         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9567     }
9568
9569     if (qstatus)
9570     {
9571         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9572         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9573            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9574            ret, msg.message, msg.wParam);
9575         qstatus = GetQueueStatus(qs_all_input);
9576         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9577     }
9578 done:
9579     trace("signalling to exit\n");
9580     SetEvent(info.hevent[EV_STOP]);
9581
9582     WaitForSingleObject(hthread, INFINITE);
9583
9584     CloseHandle(hthread);
9585     CloseHandle(info.hevent[0]);
9586     CloseHandle(info.hevent[1]);
9587     CloseHandle(info.hevent[2]);
9588
9589     DestroyWindow(info.hwnd);
9590 }
9591
9592 static void wait_move_event(HWND hwnd, int x, int y)
9593 {
9594     MSG msg;
9595     DWORD time;
9596     BOOL  ret;
9597     int go = 0;
9598
9599     time = GetTickCount();
9600     while (GetTickCount() - time < 200 && !go) {
9601         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9602         go  = ret && msg.pt.x > x && msg.pt.y > y;
9603         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9604     }
9605 }
9606
9607 #define STEP 5
9608 static void test_PeekMessage2(void)
9609 {
9610     HWND hwnd;
9611     BOOL ret;
9612     MSG msg;
9613     UINT message;
9614     DWORD time1, time2, time3;
9615     int x1, y1, x2, y2, x3, y3;
9616     POINT pos;
9617
9618     time1 = time2 = time3 = 0;
9619     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9620
9621     /* Initialise window and make sure it is ready for events */
9622     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9623                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9624     assert(hwnd);
9625     trace("Window for test_PeekMessage2 %p\n", hwnd);
9626     ShowWindow(hwnd, SW_SHOW);
9627     UpdateWindow(hwnd);
9628     SetFocus(hwnd);
9629     GetCursorPos(&pos);
9630     SetCursorPos(100, 100);
9631     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9632     flush_events();
9633
9634     /* Do initial mousemove, wait until we can see it
9635        and then do our test peek with PM_NOREMOVE. */
9636     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9637     wait_move_event(hwnd, 100-STEP, 100-STEP);
9638
9639     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9640     if (!ret)
9641     {
9642         skip( "queuing mouse events not supported\n" );
9643         goto done;
9644     }
9645     else
9646     {
9647         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9648         message = msg.message;
9649         time1 = msg.time;
9650         x1 = msg.pt.x;
9651         y1 = msg.pt.y;
9652         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9653     }
9654
9655     /* Allow time to advance a bit, and then simulate the user moving their
9656      * mouse around. After that we peek again with PM_NOREMOVE.
9657      * Although the previous mousemove message was never removed, the
9658      * mousemove we now peek should reflect the recent mouse movements
9659      * because the input queue will merge the move events. */
9660     Sleep(100);
9661     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9662     wait_move_event(hwnd, x1, y1);
9663
9664     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9665     ok(ret, "no message available\n");
9666     if (ret) {
9667         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9668         message = msg.message;
9669         time2 = msg.time;
9670         x2 = msg.pt.x;
9671         y2 = msg.pt.y;
9672         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9673         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9674         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9675     }
9676
9677     /* Have another go, to drive the point home */
9678     Sleep(100);
9679     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9680     wait_move_event(hwnd, x2, y2);
9681
9682     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9683     ok(ret, "no message available\n");
9684     if (ret) {
9685         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9686         message = msg.message;
9687         time3 = msg.time;
9688         x3 = msg.pt.x;
9689         y3 = msg.pt.y;
9690         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9691         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9692         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9693     }
9694
9695 done:
9696     DestroyWindow(hwnd);
9697     SetCursorPos(pos.x, pos.y);
9698     flush_events();
9699 }
9700
9701 static void test_quit_message(void)
9702 {
9703     MSG msg;
9704     BOOL ret;
9705
9706     /* test using PostQuitMessage */
9707     flush_events();
9708     PostQuitMessage(0xbeef);
9709
9710     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9711     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9712     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9713     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9714
9715     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9716     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9717
9718     ret = GetMessage(&msg, NULL, 0, 0);
9719     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9720     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9721
9722     /* note: WM_QUIT message received after WM_USER message */
9723     ret = GetMessage(&msg, NULL, 0, 0);
9724     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9725     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9726     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9727
9728     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9729     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9730
9731     /* now test with PostThreadMessage - different behaviour! */
9732     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9733
9734     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9735     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9736     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9737     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9738
9739     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9740     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9741
9742     /* note: we receive the WM_QUIT message first this time */
9743     ret = GetMessage(&msg, NULL, 0, 0);
9744     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9745     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9746     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9747
9748     ret = GetMessage(&msg, NULL, 0, 0);
9749     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9750     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9751 }
9752
9753 static const struct message WmMouseHoverSeq[] = {
9754     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9755     { WM_MOUSEACTIVATE, sent|optional },
9756     { WM_TIMER, sent|optional }, /* XP sends it */
9757     { WM_SYSTIMER, sent },
9758     { WM_MOUSEHOVER, sent|wparam, 0 },
9759     { 0 }
9760 };
9761
9762 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9763 {
9764     MSG msg;
9765     DWORD start_ticks, end_ticks;
9766
9767     start_ticks = GetTickCount();
9768     /* add some deviation (50%) to cover not expected delays */
9769     start_ticks += timeout / 2;
9770
9771     do
9772     {
9773         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9774         {
9775             /* Timer proc messages are not dispatched to the window proc,
9776              * and therefore not logged.
9777              */
9778             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9779             {
9780                 struct recvd_message s_msg;
9781
9782                 s_msg.hwnd = msg.hwnd;
9783                 s_msg.message = msg.message;
9784                 s_msg.flags = sent|wparam|lparam;
9785                 s_msg.wParam = msg.wParam;
9786                 s_msg.lParam = msg.lParam;
9787                 s_msg.descr = "msg_loop";
9788                 add_message(&s_msg);
9789             }
9790             DispatchMessage(&msg);
9791         }
9792
9793         end_ticks = GetTickCount();
9794
9795         /* inject WM_MOUSEMOVE to see how it changes tracking */
9796         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9797         {
9798             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9799             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9800
9801             inject_mouse_move = FALSE;
9802         }
9803     } while (start_ticks + timeout >= end_ticks);
9804 }
9805
9806 static void test_TrackMouseEvent(void)
9807 {
9808     TRACKMOUSEEVENT tme;
9809     BOOL ret;
9810     HWND hwnd, hchild;
9811     RECT rc_parent, rc_child;
9812     UINT default_hover_time, hover_width = 0, hover_height = 0;
9813
9814 #define track_hover(track_hwnd, track_hover_time) \
9815     tme.cbSize = sizeof(tme); \
9816     tme.dwFlags = TME_HOVER; \
9817     tme.hwndTrack = track_hwnd; \
9818     tme.dwHoverTime = track_hover_time; \
9819     SetLastError(0xdeadbeef); \
9820     ret = pTrackMouseEvent(&tme); \
9821     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9822
9823 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9824     tme.cbSize = sizeof(tme); \
9825     tme.dwFlags = TME_QUERY; \
9826     tme.hwndTrack = (HWND)0xdeadbeef; \
9827     tme.dwHoverTime = 0xdeadbeef; \
9828     SetLastError(0xdeadbeef); \
9829     ret = pTrackMouseEvent(&tme); \
9830     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9831     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9832     ok(tme.dwFlags == (expected_track_flags), \
9833        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9834     ok(tme.hwndTrack == (expected_track_hwnd), \
9835        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9836     ok(tme.dwHoverTime == (expected_hover_time), \
9837        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9838
9839 #define track_hover_cancel(track_hwnd) \
9840     tme.cbSize = sizeof(tme); \
9841     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9842     tme.hwndTrack = track_hwnd; \
9843     tme.dwHoverTime = 0xdeadbeef; \
9844     SetLastError(0xdeadbeef); \
9845     ret = pTrackMouseEvent(&tme); \
9846     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9847
9848     default_hover_time = 0xdeadbeef;
9849     SetLastError(0xdeadbeef);
9850     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9851     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9852        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9853     if (!ret) default_hover_time = 400;
9854     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9855
9856     SetLastError(0xdeadbeef);
9857     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9858     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9859        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9860     if (!ret) hover_width = 4;
9861     SetLastError(0xdeadbeef);
9862     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9863     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9864        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9865     if (!ret) hover_height = 4;
9866     trace("hover rect is %u x %d\n", hover_width, hover_height);
9867
9868     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9869                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9870                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9871                           NULL, NULL, 0);
9872     assert(hwnd);
9873
9874     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9875                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9876                           50, 50, 200, 200, hwnd,
9877                           NULL, NULL, 0);
9878     assert(hchild);
9879
9880     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9881     flush_events();
9882     flush_sequence();
9883
9884     tme.cbSize = 0;
9885     tme.dwFlags = TME_QUERY;
9886     tme.hwndTrack = (HWND)0xdeadbeef;
9887     tme.dwHoverTime = 0xdeadbeef;
9888     SetLastError(0xdeadbeef);
9889     ret = pTrackMouseEvent(&tme);
9890     ok(!ret, "TrackMouseEvent should fail\n");
9891     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9892        "not expected error %u\n", GetLastError());
9893
9894     tme.cbSize = sizeof(tme);
9895     tme.dwFlags = TME_HOVER;
9896     tme.hwndTrack = (HWND)0xdeadbeef;
9897     tme.dwHoverTime = 0xdeadbeef;
9898     SetLastError(0xdeadbeef);
9899     ret = pTrackMouseEvent(&tme);
9900     ok(!ret, "TrackMouseEvent should fail\n");
9901     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9902        "not expected error %u\n", GetLastError());
9903
9904     tme.cbSize = sizeof(tme);
9905     tme.dwFlags = TME_HOVER | TME_CANCEL;
9906     tme.hwndTrack = (HWND)0xdeadbeef;
9907     tme.dwHoverTime = 0xdeadbeef;
9908     SetLastError(0xdeadbeef);
9909     ret = pTrackMouseEvent(&tme);
9910     ok(!ret, "TrackMouseEvent should fail\n");
9911     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9912        "not expected error %u\n", GetLastError());
9913
9914     GetWindowRect(hwnd, &rc_parent);
9915     GetWindowRect(hchild, &rc_child);
9916     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9917
9918     /* Process messages so that the system updates its internal current
9919      * window and hittest, otherwise TrackMouseEvent calls don't have any
9920      * effect.
9921      */
9922     flush_events();
9923     flush_sequence();
9924
9925     track_query(0, NULL, 0);
9926     track_hover(hchild, 0);
9927     track_query(0, NULL, 0);
9928
9929     flush_events();
9930     flush_sequence();
9931
9932     track_hover(hwnd, 0);
9933     tme.cbSize = sizeof(tme);
9934     tme.dwFlags = TME_QUERY;
9935     tme.hwndTrack = (HWND)0xdeadbeef;
9936     tme.dwHoverTime = 0xdeadbeef;
9937     SetLastError(0xdeadbeef);
9938     ret = pTrackMouseEvent(&tme);
9939     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
9940     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
9941     if (!tme.dwFlags)
9942     {
9943         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
9944         DestroyWindow( hwnd );
9945         return;
9946     }
9947     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
9948     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
9949     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
9950        tme.dwHoverTime, default_hover_time);
9951
9952     pump_msg_loop_timeout(default_hover_time, FALSE);
9953     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9954
9955     track_query(0, NULL, 0);
9956
9957     track_hover(hwnd, HOVER_DEFAULT);
9958     track_query(TME_HOVER, hwnd, default_hover_time);
9959
9960     Sleep(default_hover_time / 2);
9961     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9962     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9963
9964     track_query(TME_HOVER, hwnd, default_hover_time);
9965
9966     pump_msg_loop_timeout(default_hover_time, FALSE);
9967     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9968
9969     track_query(0, NULL, 0);
9970
9971     track_hover(hwnd, HOVER_DEFAULT);
9972     track_query(TME_HOVER, hwnd, default_hover_time);
9973
9974     pump_msg_loop_timeout(default_hover_time, TRUE);
9975     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9976
9977     track_query(0, NULL, 0);
9978
9979     track_hover(hwnd, HOVER_DEFAULT);
9980     track_query(TME_HOVER, hwnd, default_hover_time);
9981     track_hover_cancel(hwnd);
9982
9983     DestroyWindow(hwnd);
9984
9985 #undef track_hover
9986 #undef track_query
9987 #undef track_hover_cancel
9988 }
9989
9990
9991 static const struct message WmSetWindowRgn[] = {
9992     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9993     { WM_NCCALCSIZE, sent|wparam, 1 },
9994     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9995     { WM_GETTEXT, sent|defwinproc|optional },
9996     { WM_ERASEBKGND, sent|optional },
9997     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9998     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9999     { 0 }
10000 };
10001
10002 static const struct message WmSetWindowRgn_no_redraw[] = {
10003     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10004     { WM_NCCALCSIZE, sent|wparam, 1 },
10005     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10006     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10007     { 0 }
10008 };
10009
10010 static const struct message WmSetWindowRgn_clear[] = {
10011     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10012     { WM_NCCALCSIZE, sent|wparam, 1 },
10013     { WM_NCPAINT, sent|optional },
10014     { WM_GETTEXT, sent|defwinproc|optional },
10015     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10016     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10017     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10018     { WM_NCPAINT, sent|optional },
10019     { WM_GETTEXT, sent|defwinproc|optional },
10020     { WM_ERASEBKGND, sent|optional },
10021     { WM_WINDOWPOSCHANGING, sent|optional },
10022     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10023     { WM_NCPAINT, sent|optional },
10024     { WM_GETTEXT, sent|defwinproc|optional },
10025     { WM_ERASEBKGND, sent|optional },
10026     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10027     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10028     { WM_NCPAINT, sent|optional },
10029     { WM_GETTEXT, sent|defwinproc|optional },
10030     { WM_ERASEBKGND, sent|optional },
10031     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10032     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10033     { 0 }
10034 };
10035
10036 static void test_SetWindowRgn(void)
10037 {
10038     HRGN hrgn;
10039     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10040                                 100, 100, 200, 200, 0, 0, 0, NULL);
10041     ok( hwnd != 0, "Failed to create overlapped window\n" );
10042
10043     ShowWindow( hwnd, SW_SHOW );
10044     UpdateWindow( hwnd );
10045     flush_events();
10046     flush_sequence();
10047
10048     trace("testing SetWindowRgn\n");
10049     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10050     SetWindowRgn( hwnd, hrgn, TRUE );
10051     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10052
10053     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10054     SetWindowRgn( hwnd, hrgn, FALSE );
10055     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10056
10057     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10058     SetWindowRgn( hwnd, hrgn, TRUE );
10059     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10060
10061     SetWindowRgn( hwnd, 0, TRUE );
10062     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10063
10064     DestroyWindow( hwnd );
10065 }
10066
10067 /*************************** ShowWindow() test ******************************/
10068 static const struct message WmShowNormal[] = {
10069     { WM_SHOWWINDOW, sent|wparam, 1 },
10070     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10071     { HCBT_ACTIVATE, hook },
10072     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10073     { HCBT_SETFOCUS, hook },
10074     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10075     { 0 }
10076 };
10077 static const struct message WmShow[] = {
10078     { WM_SHOWWINDOW, sent|wparam, 1 },
10079     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10080     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10081     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10082     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10083     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10084     { 0 }
10085 };
10086 static const struct message WmShowNoActivate_1[] = {
10087     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10088     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10089     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10090     { WM_MOVE, sent|defwinproc|optional },
10091     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10092     { 0 }
10093 };
10094 static const struct message WmShowNoActivate_2[] = {
10095     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10096     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10097     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10098     { WM_MOVE, sent|defwinproc },
10099     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10100     { HCBT_SETFOCUS, hook|optional },
10101     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10102     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10103     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10104     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10105     { 0 }
10106 };
10107 static const struct message WmShowNA_1[] = {
10108     { WM_SHOWWINDOW, sent|wparam, 1 },
10109     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10110     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10111     { 0 }
10112 };
10113 static const struct message WmShowNA_2[] = {
10114     { WM_SHOWWINDOW, sent|wparam, 1 },
10115     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10116     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10117     { 0 }
10118 };
10119 static const struct message WmRestore_1[] = {
10120     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10121     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10122     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10123     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10124     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10125     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10126     { WM_MOVE, sent|defwinproc },
10127     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10128     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10129     { 0 }
10130 };
10131 static const struct message WmRestore_2[] = {
10132     { WM_SHOWWINDOW, sent|wparam, 1 },
10133     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10134     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10135     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10136     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10137     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10138     { 0 }
10139 };
10140 static const struct message WmRestore_3[] = {
10141     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10142     { WM_GETMINMAXINFO, sent },
10143     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10144     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10145     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10146     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10147     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10148     { WM_MOVE, sent|defwinproc },
10149     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10150     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10151     { 0 }
10152 };
10153 static const struct message WmRestore_4[] = {
10154     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10155     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10156     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10157     { WM_MOVE, sent|defwinproc|optional },
10158     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10159     { 0 }
10160 };
10161 static const struct message WmRestore_5[] = {
10162     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10163     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10164     { HCBT_ACTIVATE, hook|optional },
10165     { HCBT_SETFOCUS, hook|optional },
10166     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10167     { WM_MOVE, sent|defwinproc|optional },
10168     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10169     { 0 }
10170 };
10171 static const struct message WmHide_1[] = {
10172     { WM_SHOWWINDOW, sent|wparam, 0 },
10173     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10174     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10175     { HCBT_ACTIVATE, hook|optional },
10176     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10177     { 0 }
10178 };
10179 static const struct message WmHide_2[] = {
10180     { WM_SHOWWINDOW, sent|wparam, 0 },
10181     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10182     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10183     { HCBT_ACTIVATE, hook|optional },
10184     { 0 }
10185 };
10186 static const struct message WmHide_3[] = {
10187     { WM_SHOWWINDOW, sent|wparam, 0 },
10188     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10189     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10190     { HCBT_SETFOCUS, hook|optional },
10191     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10192     { 0 }
10193 };
10194 static const struct message WmShowMinimized_1[] = {
10195     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10197     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10198     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10199     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10200     { WM_MOVE, sent|defwinproc },
10201     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10202     { 0 }
10203 };
10204 static const struct message WmMinimize_1[] = {
10205     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10206     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10207     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10208     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10209     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10210     { WM_MOVE, sent|defwinproc },
10211     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10212     { 0 }
10213 };
10214 static const struct message WmMinimize_2[] = {
10215     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10216     { HCBT_SETFOCUS, hook|optional },
10217     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10218     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10219     { WM_MOVE, sent|defwinproc },
10220     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10221     { 0 }
10222 };
10223 static const struct message WmMinimize_3[] = {
10224     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10225     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10226     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10227     { WM_MOVE, sent|defwinproc },
10228     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10229     { 0 }
10230 };
10231 static const struct message WmShowMinNoActivate[] = {
10232     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10233     { WM_WINDOWPOSCHANGING, sent },
10234     { WM_WINDOWPOSCHANGED, sent },
10235     { WM_MOVE, sent|defwinproc|optional },
10236     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MINIMIZED },
10237     { 0 }
10238 };
10239 static const struct message WmMinMax_1[] = {
10240     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10241     { 0 }
10242 };
10243 static const struct message WmMinMax_2[] = {
10244     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10245     { WM_GETMINMAXINFO, sent|optional },
10246     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10247     { HCBT_ACTIVATE, hook|optional },
10248     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10249     { HCBT_SETFOCUS, hook|optional },
10250     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10251     { WM_MOVE, sent|defwinproc|optional },
10252     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10253     { HCBT_SETFOCUS, hook|optional },
10254     { 0 }
10255 };
10256 static const struct message WmMinMax_3[] = {
10257     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10258     { HCBT_SETFOCUS, hook|optional },
10259     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10260     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10261     { WM_MOVE, sent|defwinproc|optional },
10262     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MINIMIZED },
10263     { 0 }
10264 };
10265 static const struct message WmMinMax_4[] = {
10266     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10267     { 0 }
10268 };
10269 static const struct message WmShowMaximized_1[] = {
10270     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10271     { WM_GETMINMAXINFO, sent },
10272     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10273     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10274     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10275     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10276     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10277     { WM_MOVE, sent|defwinproc },
10278     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10279     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10280     { 0 }
10281 };
10282 static const struct message WmShowMaximized_2[] = {
10283     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10284     { WM_GETMINMAXINFO, sent },
10285     { WM_WINDOWPOSCHANGING, sent|optional },
10286     { HCBT_ACTIVATE, hook|optional },
10287     { WM_WINDOWPOSCHANGED, sent|optional },
10288     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10289     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10290     { WM_WINDOWPOSCHANGING, sent|optional },
10291     { HCBT_SETFOCUS, hook|optional },
10292     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10293     { WM_MOVE, sent|defwinproc },
10294     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10295     { HCBT_SETFOCUS, hook|optional },
10296     { 0 }
10297 };
10298 static const struct message WmShowMaximized_3[] = {
10299     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10300     { WM_GETMINMAXINFO, sent|optional },
10301     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10302     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10303     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10304     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10305     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10306     { WM_MOVE, sent|defwinproc|optional },
10307     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10308     { 0 }
10309 };
10310
10311 static void test_ShowWindow(void)
10312 {
10313     /* ShowWindow commands in random order */
10314     static const struct
10315     {
10316         INT cmd; /* ShowWindow command */
10317         LPARAM ret; /* ShowWindow return value */
10318         DWORD style; /* window style after the command */
10319         const struct message *msg; /* message sequence the command produces */
10320         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10321     } sw[] =
10322     {
10323 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10324 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10325 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10326 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10327 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10328 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10329 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10330 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10331 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10332 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10333 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10334 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10335 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10336 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10337 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10338 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10339 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10340 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10341 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10342 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10343 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10344 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10345 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10346 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10347 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10348 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10349 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10350 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10351 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10352 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10353 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10354 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10355 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10356 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10357 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10358 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10359 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10360 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10361 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10362 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10363 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10364 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE },
10365 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10366 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10367 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10368 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10369 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10370 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10371 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10372 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10373 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10374 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10375 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10376 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10377 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10378 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10379 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10380     };
10381     HWND hwnd;
10382     DWORD style;
10383     LPARAM ret;
10384     INT i;
10385
10386 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10387     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10388                           120, 120, 90, 90,
10389                           0, 0, 0, NULL);
10390     assert(hwnd);
10391
10392     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10393     ok(style == 0, "expected style 0, got %08x\n", style);
10394
10395     flush_events();
10396     flush_sequence();
10397
10398     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10399     {
10400         static const char * const sw_cmd_name[13] =
10401         {
10402             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10403             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10404             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10405             "SW_NORMALNA" /* 0xCC */
10406         };
10407         char comment[64];
10408         INT idx; /* index into the above array of names */
10409
10410         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10411
10412         style = GetWindowLong(hwnd, GWL_STYLE);
10413         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10414         ret = ShowWindow(hwnd, sw[i].cmd);
10415         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10416         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10417         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10418
10419         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10420         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10421
10422         flush_events();
10423         flush_sequence();
10424     }
10425
10426     DestroyWindow(hwnd);
10427 }
10428
10429 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10430 {
10431     struct recvd_message msg;
10432
10433     if (ignore_message( message )) return 0;
10434
10435     msg.hwnd = hwnd;
10436     msg.message = message;
10437     msg.flags = sent|wparam|lparam;
10438     msg.wParam = wParam;
10439     msg.lParam = lParam;
10440     msg.descr = "dialog";
10441     add_message(&msg);
10442
10443     /* calling DefDlgProc leads to a recursion under XP */
10444
10445     switch (message)
10446     {
10447     case WM_INITDIALOG:
10448     case WM_GETDLGCODE:
10449         return 0;
10450     }
10451     return 1;
10452 }
10453
10454 static const struct message WmDefDlgSetFocus_1[] = {
10455     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10456     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10457     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10458     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10459     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10460     { HCBT_SETFOCUS, hook },
10461     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10462     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10463     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10464     { WM_SETFOCUS, sent|wparam, 0 },
10465     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10466     { WM_CTLCOLOREDIT, sent },
10467     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10468     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10469     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10470     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10471     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10472     { 0 }
10473 };
10474 static const struct message WmDefDlgSetFocus_2[] = {
10475     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10476     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10477     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10478     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10479     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10480     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10481     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10482     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10483     { 0 }
10484 };
10485 /* Creation of a dialog */
10486 static const struct message WmCreateDialogParamSeq_1[] = {
10487     { HCBT_CREATEWND, hook },
10488     { WM_NCCREATE, sent },
10489     { WM_NCCALCSIZE, sent|wparam, 0 },
10490     { WM_CREATE, sent },
10491     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10492     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10493     { WM_MOVE, sent },
10494     { WM_SETFONT, sent },
10495     { WM_INITDIALOG, sent },
10496     { WM_CHANGEUISTATE, sent|optional },
10497     { 0 }
10498 };
10499 /* Creation of a dialog */
10500 static const struct message WmCreateDialogParamSeq_2[] = {
10501     { HCBT_CREATEWND, hook },
10502     { WM_NCCREATE, sent },
10503     { WM_NCCALCSIZE, sent|wparam, 0 },
10504     { WM_CREATE, sent },
10505     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10506     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10507     { WM_MOVE, sent },
10508     { WM_CHANGEUISTATE, sent|optional },
10509     { 0 }
10510 };
10511
10512 static void test_dialog_messages(void)
10513 {
10514     WNDCLASS cls;
10515     HWND hdlg, hedit1, hedit2, hfocus;
10516     LRESULT ret;
10517
10518 #define set_selection(hctl, start, end) \
10519     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10520     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10521
10522 #define check_selection(hctl, start, end) \
10523     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10524     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10525
10526     subclass_edit();
10527
10528     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10529                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10530                           0, 0, 100, 100, 0, 0, 0, NULL);
10531     ok(hdlg != 0, "Failed to create custom dialog window\n");
10532
10533     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10534                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10535                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10536     ok(hedit1 != 0, "Failed to create edit control\n");
10537     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10538                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10539                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10540     ok(hedit2 != 0, "Failed to create edit control\n");
10541
10542     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10543     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10544
10545     hfocus = GetFocus();
10546     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10547
10548     SetFocus(hedit2);
10549     hfocus = GetFocus();
10550     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10551
10552     check_selection(hedit1, 0, 0);
10553     check_selection(hedit2, 0, 0);
10554
10555     set_selection(hedit2, 0, -1);
10556     check_selection(hedit2, 0, 3);
10557
10558     SetFocus(0);
10559     hfocus = GetFocus();
10560     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10561
10562     flush_sequence();
10563     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10564     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10565     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10566
10567     hfocus = GetFocus();
10568     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10569
10570     check_selection(hedit1, 0, 5);
10571     check_selection(hedit2, 0, 3);
10572
10573     flush_sequence();
10574     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10575     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10576     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10577
10578     hfocus = GetFocus();
10579     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10580
10581     check_selection(hedit1, 0, 5);
10582     check_selection(hedit2, 0, 3);
10583
10584     EndDialog(hdlg, 0);
10585     DestroyWindow(hedit1);
10586     DestroyWindow(hedit2);
10587     DestroyWindow(hdlg);
10588     flush_sequence();
10589
10590 #undef set_selection
10591 #undef check_selection
10592
10593     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10594     cls.lpszClassName = "MyDialogClass";
10595     cls.hInstance = GetModuleHandle(0);
10596     /* need a cast since a dlgproc is used as a wndproc */
10597     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10598     if (!RegisterClass(&cls)) assert(0);
10599
10600     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10601     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10602     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10603     EndDialog(hdlg, 0);
10604     DestroyWindow(hdlg);
10605     flush_sequence();
10606
10607     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10608     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10609     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10610     EndDialog(hdlg, 0);
10611     DestroyWindow(hdlg);
10612     flush_sequence();
10613
10614     UnregisterClass(cls.lpszClassName, cls.hInstance);
10615 }
10616
10617 static void test_nullCallback(void)
10618 {
10619     HWND hwnd;
10620
10621     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10622                            100, 100, 200, 200, 0, 0, 0, NULL);
10623     ok (hwnd != 0, "Failed to create overlapped window\n");
10624
10625     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10626     flush_events();
10627     DestroyWindow(hwnd);
10628 }
10629
10630 /* SetActiveWindow( 0 ) hwnd visible */
10631 static const struct message SetActiveWindowSeq0[] =
10632 {
10633     { HCBT_ACTIVATE, hook|optional },
10634     { WM_NCACTIVATE, sent|wparam, 0 },
10635     { WM_GETTEXT, sent|defwinproc|optional },
10636     { WM_ACTIVATE, sent|wparam, 0 },
10637     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10638     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10639     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10640     { WM_KILLFOCUS, sent|optional },
10641     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10642     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10643     { WM_NCACTIVATE, sent|wparam|optional, 1 },
10644     { WM_GETTEXT, sent|defwinproc|optional },
10645     { WM_ACTIVATE, sent|wparam|optional, 1 },
10646     { HCBT_SETFOCUS, hook|optional },
10647     { WM_KILLFOCUS, sent|defwinproc|optional },
10648     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10649     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10650     { WM_IME_SETCONTEXT, sent|optional },
10651     { WM_IME_SETCONTEXT, sent|optional },
10652     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10653     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10654     { WM_SETFOCUS, sent|defwinproc|optional },
10655     { WM_GETTEXT, sent|optional },
10656     { 0 }
10657 };
10658 /* SetActiveWindow( hwnd ) hwnd visible */
10659 static const struct message SetActiveWindowSeq1[] =
10660 {
10661     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10662     { 0 }
10663 };
10664 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10665 static const struct message SetActiveWindowSeq2[] =
10666 {
10667     { HCBT_ACTIVATE, hook },
10668     { WM_NCACTIVATE, sent|wparam, 0 },
10669     { WM_GETTEXT, sent|defwinproc|optional },
10670     { WM_ACTIVATE, sent|wparam, 0 },
10671     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10672     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10673     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10674     { WM_NCPAINT, sent|optional },
10675     { WM_GETTEXT, sent|defwinproc|optional },
10676     { WM_ERASEBKGND, sent|optional },
10677     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10678     { WM_NCACTIVATE, sent|wparam, 1 },
10679     { WM_GETTEXT, sent|defwinproc|optional },
10680     { WM_ACTIVATE, sent|wparam, 1 },
10681     { HCBT_SETFOCUS, hook },
10682     { WM_KILLFOCUS, sent|defwinproc },
10683     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10684     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10685     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10686     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10687     { WM_SETFOCUS, sent|defwinproc },
10688     { WM_GETTEXT, sent|optional },
10689     { 0 }
10690 };
10691
10692 /* SetActiveWindow( hwnd ) hwnd not visible */
10693 static const struct message SetActiveWindowSeq3[] =
10694 {
10695     { HCBT_ACTIVATE, hook },
10696     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10697     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10698     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10699     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10700     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10701     { WM_ACTIVATEAPP, sent|wparam, 1 },
10702     { WM_ACTIVATEAPP, sent|wparam, 1 },
10703     { WM_NCACTIVATE, sent|wparam, 1 },
10704     { WM_ACTIVATE, sent|wparam, 1 },
10705     { HCBT_SETFOCUS, hook },
10706     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10707     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10708     { WM_SETFOCUS, sent|defwinproc },
10709     { 0 }
10710 };
10711 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10712 static const struct message SetActiveWindowSeq4[] =
10713 {
10714     { HCBT_ACTIVATE, hook },
10715     { WM_NCACTIVATE, sent|wparam, 0 },
10716     { WM_GETTEXT, sent|defwinproc|optional },
10717     { WM_ACTIVATE, sent|wparam, 0 },
10718     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10719     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10720     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10721     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10722     { WM_NCACTIVATE, sent|wparam, 1 },
10723     { WM_GETTEXT, sent|defwinproc|optional },
10724     { WM_ACTIVATE, sent|wparam, 1 },
10725     { HCBT_SETFOCUS, hook },
10726     { WM_KILLFOCUS, sent|defwinproc },
10727     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10728     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10729     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10730     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10731     { WM_SETFOCUS, sent|defwinproc },
10732     { 0 }
10733 };
10734
10735
10736 static void test_SetActiveWindow(void)
10737 {
10738     HWND hwnd, popup, ret;
10739
10740     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10741                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10742                            100, 100, 200, 200, 0, 0, 0, NULL);
10743
10744     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10745                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10746                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10747
10748     ok(hwnd != 0, "Failed to create overlapped window\n");
10749     ok(popup != 0, "Failed to create popup window\n");
10750     SetForegroundWindow( popup );
10751     flush_sequence();
10752
10753     trace("SetActiveWindow(0)\n");
10754     ret = SetActiveWindow(0);
10755     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10756     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
10757     flush_sequence();
10758
10759     trace("SetActiveWindow(hwnd), hwnd visible\n");
10760     ret = SetActiveWindow(hwnd);
10761     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10762     flush_sequence();
10763
10764     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10765     ret = SetActiveWindow(popup);
10766     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10767     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10768     flush_sequence();
10769
10770     ShowWindow(hwnd, SW_HIDE);
10771     ShowWindow(popup, SW_HIDE);
10772     flush_sequence();
10773
10774     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10775     ret = SetActiveWindow(hwnd);
10776     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
10777     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10778     flush_sequence();
10779
10780     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10781     ret = SetActiveWindow(popup);
10782     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10783     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10784     flush_sequence();
10785
10786     trace("done\n");
10787
10788     DestroyWindow(hwnd);
10789 }
10790
10791 static const struct message SetForegroundWindowSeq[] =
10792 {
10793     { WM_NCACTIVATE, sent|wparam, 0 },
10794     { WM_GETTEXT, sent|defwinproc|optional },
10795     { WM_ACTIVATE, sent|wparam, 0 },
10796     { WM_ACTIVATEAPP, sent|wparam, 0 },
10797     { WM_KILLFOCUS, sent },
10798     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10799     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10800     { 0 }
10801 };
10802
10803 static void test_SetForegroundWindow(void)
10804 {
10805     HWND hwnd;
10806
10807     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10808                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10809                            100, 100, 200, 200, 0, 0, 0, NULL);
10810     ok (hwnd != 0, "Failed to create overlapped window\n");
10811     SetForegroundWindow( hwnd );
10812     flush_sequence();
10813
10814     trace("SetForegroundWindow( 0 )\n");
10815     SetForegroundWindow( 0 );
10816     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10817     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10818     SetForegroundWindow( GetDesktopWindow() );
10819     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10820                                         "foreground top level window", FALSE);
10821     trace("done\n");
10822
10823     DestroyWindow(hwnd);
10824 }
10825
10826 static void test_dbcs_wm_char(void)
10827 {
10828     BYTE dbch[2];
10829     WCHAR wch, bad_wch;
10830     HWND hwnd, hwnd2;
10831     MSG msg;
10832     DWORD time;
10833     POINT pt;
10834     DWORD_PTR res;
10835     CPINFOEXA cpinfo;
10836     UINT i, j, k;
10837     struct message wmCharSeq[2];
10838
10839     if (!pGetCPInfoExA)
10840     {
10841         win_skip("GetCPInfoExA is not available\n");
10842         return;
10843     }
10844
10845     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10846     if (cpinfo.MaxCharSize != 2)
10847     {
10848         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10849         return;
10850     }
10851
10852     dbch[0] = dbch[1] = 0;
10853     wch = 0;
10854     bad_wch = cpinfo.UnicodeDefaultChar;
10855     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10856         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10857             for (k = 128; k <= 255; k++)
10858             {
10859                 char str[2];
10860                 WCHAR wstr[2];
10861                 str[0] = j;
10862                 str[1] = k;
10863                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10864                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10865                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10866                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10867                 {
10868                     dbch[0] = j;
10869                     dbch[1] = k;
10870                     wch = wstr[0];
10871                     break;
10872                 }
10873             }
10874
10875     if (!wch)
10876     {
10877         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10878         return;
10879     }
10880     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10881            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10882
10883     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10884                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10885     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10886                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10887     ok (hwnd != 0, "Failed to create overlapped window\n");
10888     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10889     flush_sequence();
10890
10891     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10892     wmCharSeq[0].message = WM_CHAR;
10893     wmCharSeq[0].flags = sent|wparam;
10894     wmCharSeq[0].wParam = wch;
10895
10896     /* posted message */
10897     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10898     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10899     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10900     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10901     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10902     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10903     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10904
10905     /* posted thread message */
10906     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10907     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10908     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10909     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10910     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10911     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10912     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10913
10914     /* sent message */
10915     flush_sequence();
10916     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10917     ok_sequence( WmEmptySeq, "no messages", FALSE );
10918     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10919     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10920     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10921
10922     /* sent message with timeout */
10923     flush_sequence();
10924     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10925     ok_sequence( WmEmptySeq, "no messages", FALSE );
10926     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10927     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10928     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10929
10930     /* sent message with timeout and callback */
10931     flush_sequence();
10932     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10933     ok_sequence( WmEmptySeq, "no messages", FALSE );
10934     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10935     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10936     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10937
10938     /* sent message with callback */
10939     flush_sequence();
10940     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10941     ok_sequence( WmEmptySeq, "no messages", FALSE );
10942     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10943     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10944     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10945
10946     /* direct window proc call */
10947     flush_sequence();
10948     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10949     ok_sequence( WmEmptySeq, "no messages", FALSE );
10950     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10951     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10952
10953     /* dispatch message */
10954     msg.hwnd = hwnd;
10955     msg.message = WM_CHAR;
10956     msg.wParam = dbch[0];
10957     msg.lParam = 0;
10958     DispatchMessageA( &msg );
10959     ok_sequence( WmEmptySeq, "no messages", FALSE );
10960     msg.wParam = dbch[1];
10961     DispatchMessageA( &msg );
10962     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10963
10964     /* window handle is irrelevant */
10965     flush_sequence();
10966     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10967     ok_sequence( WmEmptySeq, "no messages", FALSE );
10968     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10969     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10970     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10971
10972     /* interleaved post and send */
10973     flush_sequence();
10974     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10975     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10976     ok_sequence( WmEmptySeq, "no messages", FALSE );
10977     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10978     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10979     ok_sequence( WmEmptySeq, "no messages", FALSE );
10980     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10981     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10982     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10983     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10984     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10985     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10986     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10987
10988     /* interleaved sent message and winproc */
10989     flush_sequence();
10990     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10991     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10992     ok_sequence( WmEmptySeq, "no messages", FALSE );
10993     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10994     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10995     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10996     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10997
10998     /* interleaved winproc and dispatch */
10999     msg.hwnd = hwnd;
11000     msg.message = WM_CHAR;
11001     msg.wParam = dbch[0];
11002     msg.lParam = 0;
11003     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11004     DispatchMessageA( &msg );
11005     ok_sequence( WmEmptySeq, "no messages", FALSE );
11006     msg.wParam = dbch[1];
11007     DispatchMessageA( &msg );
11008     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11009     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11010     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11011
11012     /* interleaved sends */
11013     flush_sequence();
11014     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11015     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11016     ok_sequence( WmEmptySeq, "no messages", FALSE );
11017     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11018     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11019     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11020     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11021
11022     /* dbcs WM_CHAR */
11023     flush_sequence();
11024     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11025     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11026     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11027
11028     /* other char messages are not magic */
11029     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11030     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11031     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11032     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11033     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11034     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11035     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11036     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11037     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11038     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11039
11040     /* test retrieving messages */
11041
11042     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11043     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11044     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11045     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11046     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11047     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11048     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11049     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11050     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11051     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11052
11053     /* message filters */
11054     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11055     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11056     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11057     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11058     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11059     /* message id is filtered, hwnd is not */
11060     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
11061     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
11062     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11063     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11064     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11065     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11066
11067     /* mixing GetMessage and PostMessage */
11068     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11069     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
11070     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11071     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11072     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11073     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11074     time = msg.time;
11075     pt = msg.pt;
11076     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11077     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11078     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11079     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11080     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11081     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11082     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11083     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 );
11084     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11085
11086     /* without PM_REMOVE */
11087     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11088     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11089     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11090     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11091     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11092     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11093     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11094     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11095     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11096     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11097     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11098     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11099     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11100     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11101     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11102     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11103     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11104     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11105
11106     DestroyWindow(hwnd);
11107 }
11108
11109 #define ID_LISTBOX 0x000f
11110
11111 static const struct message wm_lb_setcursel_0[] =
11112 {
11113     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11114     { WM_CTLCOLORLISTBOX, sent|parent },
11115     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11116     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11117     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11118     { 0 }
11119 };
11120 static const struct message wm_lb_setcursel_1[] =
11121 {
11122     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11123     { WM_CTLCOLORLISTBOX, sent|parent },
11124     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11125     { WM_CTLCOLORLISTBOX, sent|parent },
11126     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11127     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11128     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11129     { 0 }
11130 };
11131 static const struct message wm_lb_setcursel_2[] =
11132 {
11133     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11134     { WM_CTLCOLORLISTBOX, sent|parent },
11135     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11136     { WM_CTLCOLORLISTBOX, sent|parent },
11137     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11138     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11139     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11140     { 0 }
11141 };
11142 static const struct message wm_lb_click_0[] =
11143 {
11144     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11145     { HCBT_SETFOCUS, hook },
11146     { WM_KILLFOCUS, sent|parent },
11147     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11148     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11149     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11150     { WM_SETFOCUS, sent|defwinproc },
11151
11152     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11153     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11154     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11155     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11156     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11157
11158     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11159     { WM_CTLCOLORLISTBOX, sent|parent },
11160     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11161     { WM_CTLCOLORLISTBOX, sent|parent },
11162     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11163     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11164
11165     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11166     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11167
11168     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11169     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11170     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11171     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11172     { 0 }
11173 };
11174 static const struct message wm_lb_deletestring[] =
11175 {
11176     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11177     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11178     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11179     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11180     { 0 }
11181 };
11182 static const struct message wm_lb_deletestring_reset[] =
11183 {
11184     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11185     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11186     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11187     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11188     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11189     { 0 }
11190 };
11191
11192 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11193
11194 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11195
11196 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11197 {
11198     static LONG defwndproc_counter = 0;
11199     LRESULT ret;
11200     struct recvd_message msg;
11201
11202     /* do not log painting messages */
11203     if (message != WM_PAINT &&
11204         message != WM_NCPAINT &&
11205         message != WM_SYNCPAINT &&
11206         message != WM_ERASEBKGND &&
11207         message != WM_NCHITTEST &&
11208         message != WM_GETTEXT &&
11209         !ignore_message( message ))
11210     {
11211         msg.hwnd = hwnd;
11212         msg.message = message;
11213         msg.flags = sent|wparam|lparam;
11214         if (defwndproc_counter) msg.flags |= defwinproc;
11215         msg.wParam = wp;
11216         msg.lParam = lp;
11217         msg.descr = "listbox";
11218         add_message(&msg);
11219     }
11220
11221     defwndproc_counter++;
11222     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11223     defwndproc_counter--;
11224
11225     return ret;
11226 }
11227
11228 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11229                                int caret_index, int top_index, int line)
11230 {
11231     LRESULT ret;
11232
11233     /* calling an orig proc helps to avoid unnecessary message logging */
11234     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11235     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11236     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11237     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11238     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11239     ok_(__FILE__, line)(ret == caret_index ||
11240                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11241                         "expected caret index %d, got %ld\n", caret_index, ret);
11242     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11243     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11244 }
11245
11246 static void test_listbox_messages(void)
11247 {
11248     HWND parent, listbox;
11249     LRESULT ret;
11250
11251     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11252                              100, 100, 200, 200, 0, 0, 0, NULL);
11253     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11254                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11255                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11256     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11257
11258     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11259
11260     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11261     ok(ret == 0, "expected 0, got %ld\n", ret);
11262     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11263     ok(ret == 1, "expected 1, got %ld\n", ret);
11264     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11265     ok(ret == 2, "expected 2, got %ld\n", ret);
11266
11267     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11268
11269     flush_sequence();
11270
11271     log_all_parent_messages++;
11272
11273     trace("selecting item 0\n");
11274     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11275     ok(ret == 0, "expected 0, got %ld\n", ret);
11276     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11277     check_lb_state(listbox, 3, 0, 0, 0);
11278     flush_sequence();
11279
11280     trace("selecting item 1\n");
11281     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11282     ok(ret == 1, "expected 1, got %ld\n", ret);
11283     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11284     check_lb_state(listbox, 3, 1, 1, 0);
11285
11286     trace("selecting item 2\n");
11287     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11288     ok(ret == 2, "expected 2, got %ld\n", ret);
11289     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11290     check_lb_state(listbox, 3, 2, 2, 0);
11291
11292     trace("clicking on item 0\n");
11293     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11294     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11295     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11296     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11297     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11298     check_lb_state(listbox, 3, 0, 0, 0);
11299     flush_sequence();
11300
11301     trace("deleting item 0\n");
11302     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11303     ok(ret == 2, "expected 2, got %ld\n", ret);
11304     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11305     check_lb_state(listbox, 2, -1, 0, 0);
11306     flush_sequence();
11307
11308     trace("deleting item 0\n");
11309     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11310     ok(ret == 1, "expected 1, got %ld\n", ret);
11311     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11312     check_lb_state(listbox, 1, -1, 0, 0);
11313     flush_sequence();
11314
11315     trace("deleting item 0\n");
11316     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11317     ok(ret == 0, "expected 0, got %ld\n", ret);
11318     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11319     check_lb_state(listbox, 0, -1, 0, 0);
11320     flush_sequence();
11321
11322     trace("deleting item 0\n");
11323     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11324     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11325     check_lb_state(listbox, 0, -1, 0, 0);
11326     flush_sequence();
11327
11328     log_all_parent_messages--;
11329
11330     DestroyWindow(listbox);
11331     DestroyWindow(parent);
11332 }
11333
11334 /*************************** Menu test ******************************/
11335 static const struct message wm_popup_menu_1[] =
11336 {
11337     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11338     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11339     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11340     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11341     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11342     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11343     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11344     { WM_INITMENU, sent|lparam, 0, 0 },
11345     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11346     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11347     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11348     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11349     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11350     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11351     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11352     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11353     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11354     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11355     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11356     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11357     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11358     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11359     { 0 }
11360 };
11361 static const struct message wm_popup_menu_2[] =
11362 {
11363     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11364     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11365     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11366     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11367     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11368     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11369     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11370     { WM_INITMENU, sent|lparam, 0, 0 },
11371     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11372     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11373     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11374     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11375     { HCBT_CREATEWND, hook },
11376     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11377                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11378     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11379     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11380     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11381     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11382     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11383     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11384     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11385     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11386     { HCBT_DESTROYWND, hook },
11387     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11388     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11389     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11390     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11391     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11392     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11393     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11394     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11395     { 0 }
11396 };
11397 static const struct message wm_popup_menu_3[] =
11398 {
11399     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11400     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11401     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11402     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11403     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11404     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11405     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11406     { WM_INITMENU, sent|lparam, 0, 0 },
11407     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11408     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11409     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11410     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11411     { HCBT_CREATEWND, hook },
11412     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11413                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11414     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11415     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11416     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11417     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11418     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11419     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11420     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11421     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11422     { HCBT_DESTROYWND, hook },
11423     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11424     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11425     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11426     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11427     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11428     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11429     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11430     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11431     { 0 }
11432 };
11433
11434 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11435 {
11436     if (message == WM_ENTERIDLE ||
11437         message == WM_INITMENU ||
11438         message == WM_INITMENUPOPUP ||
11439         message == WM_MENUSELECT ||
11440         message == WM_PARENTNOTIFY ||
11441         message == WM_ENTERMENULOOP ||
11442         message == WM_EXITMENULOOP ||
11443         message == WM_UNINITMENUPOPUP ||
11444         message == WM_KEYDOWN ||
11445         message == WM_KEYUP ||
11446         message == WM_CHAR ||
11447         message == WM_SYSKEYDOWN ||
11448         message == WM_SYSKEYUP ||
11449         message == WM_SYSCHAR ||
11450         message == WM_COMMAND ||
11451         message == WM_MENUCOMMAND)
11452     {
11453         struct recvd_message msg;
11454
11455         msg.hwnd = hwnd;
11456         msg.message = message;
11457         msg.flags = sent|wparam|lparam;
11458         msg.wParam = wp;
11459         msg.lParam = lp;
11460         msg.descr = "parent_menu_proc";
11461         add_message(&msg);
11462     }
11463
11464     return DefWindowProcA(hwnd, message, wp, lp);
11465 }
11466
11467 static void set_menu_style(HMENU hmenu, DWORD style)
11468 {
11469     MENUINFO mi;
11470     BOOL ret;
11471
11472     mi.cbSize = sizeof(mi);
11473     mi.fMask = MIM_STYLE;
11474     mi.dwStyle = style;
11475     SetLastError(0xdeadbeef);
11476     ret = pSetMenuInfo(hmenu, &mi);
11477     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11478 }
11479
11480 static DWORD get_menu_style(HMENU hmenu)
11481 {
11482     MENUINFO mi;
11483     BOOL ret;
11484
11485     mi.cbSize = sizeof(mi);
11486     mi.fMask = MIM_STYLE;
11487     mi.dwStyle = 0;
11488     SetLastError(0xdeadbeef);
11489     ret = pGetMenuInfo(hmenu, &mi);
11490     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11491
11492     return mi.dwStyle;
11493 }
11494
11495 static void test_menu_messages(void)
11496 {
11497     MSG msg;
11498     WNDCLASSA cls;
11499     HMENU hmenu, hmenu_popup;
11500     HWND hwnd;
11501     DWORD style;
11502
11503     if (!pGetMenuInfo || !pSetMenuInfo)
11504     {
11505         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11506         return;
11507     }
11508     cls.style = 0;
11509     cls.lpfnWndProc = parent_menu_proc;
11510     cls.cbClsExtra = 0;
11511     cls.cbWndExtra = 0;
11512     cls.hInstance = GetModuleHandleA(0);
11513     cls.hIcon = 0;
11514     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11515     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11516     cls.lpszMenuName = NULL;
11517     cls.lpszClassName = "TestMenuClass";
11518     UnregisterClass(cls.lpszClassName, cls.hInstance);
11519     if (!RegisterClassA(&cls)) assert(0);
11520
11521     SetLastError(0xdeadbeef);
11522     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11523                            100, 100, 200, 200, 0, 0, 0, NULL);
11524     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11525
11526     SetLastError(0xdeadbeef);
11527     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11528     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11529
11530     SetMenu(hwnd, hmenu);
11531     SetForegroundWindow( hwnd );
11532
11533     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11534     style = get_menu_style(hmenu);
11535     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11536
11537     hmenu_popup = GetSubMenu(hmenu, 0);
11538     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11539     style = get_menu_style(hmenu_popup);
11540     ok(style == 0, "expected 0, got %u\n", style);
11541
11542     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11543     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11544     style = get_menu_style(hmenu_popup);
11545     ok(style == 0, "expected 0, got %u\n", style);
11546
11547     /* Alt+E, Enter */
11548     trace("testing a popup menu command\n");
11549     flush_sequence();
11550     keybd_event(VK_MENU, 0, 0, 0);
11551     keybd_event('E', 0, 0, 0);
11552     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11553     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11554     keybd_event(VK_RETURN, 0, 0, 0);
11555     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11556     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11557     {
11558         TranslateMessage(&msg);
11559         DispatchMessage(&msg);
11560     }
11561     if (!sequence_cnt)  /* we didn't get any message */
11562     {
11563         skip( "queuing key events not supported\n" );
11564         goto done;
11565     }
11566     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
11567     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
11568     {
11569         win_skip( "menu tracking through VK_MENU not supported\n" );
11570         goto done;
11571     }
11572     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11573
11574     /* Alt+F, Right, Enter */
11575     trace("testing submenu of a popup menu command\n");
11576     flush_sequence();
11577     keybd_event(VK_MENU, 0, 0, 0);
11578     keybd_event('F', 0, 0, 0);
11579     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11580     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11581     keybd_event(VK_RIGHT, 0, 0, 0);
11582     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11583     keybd_event(VK_RETURN, 0, 0, 0);
11584     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11585     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11586     {
11587         TranslateMessage(&msg);
11588         DispatchMessage(&msg);
11589     }
11590     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11591
11592     set_menu_style(hmenu, 0);
11593     style = get_menu_style(hmenu);
11594     ok(style == 0, "expected 0, got %u\n", style);
11595
11596     hmenu_popup = GetSubMenu(hmenu, 0);
11597     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11598     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11599     style = get_menu_style(hmenu_popup);
11600     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11601
11602     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11603     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11604     style = get_menu_style(hmenu_popup);
11605     ok(style == 0, "expected 0, got %u\n", style);
11606
11607     /* Alt+F, Right, Enter */
11608     trace("testing submenu of a popup menu command\n");
11609     flush_sequence();
11610     keybd_event(VK_MENU, 0, 0, 0);
11611     keybd_event('F', 0, 0, 0);
11612     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11613     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11614     keybd_event(VK_RIGHT, 0, 0, 0);
11615     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11616     keybd_event(VK_RETURN, 0, 0, 0);
11617     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11618     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11619     {
11620         TranslateMessage(&msg);
11621         DispatchMessage(&msg);
11622     }
11623     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11624
11625 done:
11626     DestroyWindow(hwnd);
11627     DestroyMenu(hmenu);
11628 }
11629
11630
11631 static void test_paintingloop(void)
11632 {
11633     HWND hwnd;
11634
11635     paint_loop_done = 0;
11636     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11637                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11638                                 100, 100, 100, 100, 0, 0, 0, NULL );
11639     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11640     ShowWindow(hwnd,SW_NORMAL);
11641     SetFocus(hwnd);
11642
11643     while (!paint_loop_done)
11644     {
11645         MSG msg;
11646         if (PeekMessageA(&msg, 0, 0, 0, 1))
11647         {
11648             TranslateMessage(&msg);
11649             DispatchMessage(&msg);
11650         }
11651     }
11652     DestroyWindow(hwnd);
11653 }
11654
11655 static void test_defwinproc(void)
11656 {
11657     HWND hwnd;
11658     MSG msg;
11659     int gotwmquit = FALSE;
11660     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
11661     assert(hwnd);
11662     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
11663     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
11664         if( msg.message == WM_QUIT) gotwmquit = TRUE;
11665         DispatchMessageA( &msg );
11666     }
11667     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
11668     DestroyWindow( hwnd);
11669 }
11670
11671 static void test_PostMessage(void)
11672 {
11673     static const struct
11674     {
11675         HWND hwnd;
11676         BOOL ret;
11677     } data[] =
11678     {
11679         { HWND_TOP /* 0 */, TRUE },
11680         { HWND_BROADCAST, TRUE },
11681         { HWND_BOTTOM, TRUE },
11682         { HWND_TOPMOST, TRUE },
11683         { HWND_NOTOPMOST, FALSE },
11684         { HWND_MESSAGE, FALSE },
11685         { (HWND)0xdeadbeef, FALSE }
11686     };
11687     int i;
11688     HWND hwnd;
11689     BOOL ret;
11690     MSG msg;
11691     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
11692
11693     SetLastError(0xdeadbeef);
11694     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11695     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
11696     {
11697         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
11698         return;
11699     }
11700     assert(hwnd);
11701
11702     flush_events();
11703
11704     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
11705     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
11706
11707     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
11708     {
11709         memset(&msg, 0xab, sizeof(msg));
11710         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
11711         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
11712         if (data[i].ret)
11713         {
11714             if (data[i].hwnd)
11715                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
11716                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
11717                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
11718                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
11719             else
11720                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
11721                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
11722                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
11723                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
11724         }
11725     }
11726
11727     DestroyWindow(hwnd);
11728     flush_events();
11729 }
11730
11731 START_TEST(msg)
11732 {
11733     BOOL ret;
11734     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11735
11736     init_procs();
11737
11738     if (!RegisterWindowClasses()) assert(0);
11739
11740     if (pSetWinEventHook)
11741     {
11742         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11743                                        GetModuleHandleA(0), win_event_proc,
11744                                        0, GetCurrentThreadId(),
11745                                        WINEVENT_INCONTEXT);
11746         if (pIsWinEventHookInstalled && hEvent_hook)
11747         {
11748             UINT event;
11749             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11750                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11751         }
11752     }
11753     if (!hEvent_hook) win_skip( "no win event hook support\n" );
11754
11755     cbt_hook_thread_id = GetCurrentThreadId();
11756     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11757     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
11758
11759     test_winevents();
11760
11761     /* Fix message sequences before removing 4 lines below */
11762 #if 1
11763     if (pUnhookWinEvent && hEvent_hook)
11764     {
11765         ret = pUnhookWinEvent(hEvent_hook);
11766         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11767         pUnhookWinEvent = 0;
11768     }
11769     hEvent_hook = 0;
11770 #endif
11771
11772     test_PostMessage();
11773     test_ShowWindow();
11774     test_PeekMessage();
11775     test_PeekMessage2();
11776     test_scrollwindowex();
11777     test_messages();
11778     test_setwindowpos();
11779     test_showwindow();
11780     invisible_parent_tests();
11781     test_mdi_messages();
11782     test_button_messages();
11783     test_static_messages();
11784     test_listbox_messages();
11785     test_combobox_messages();
11786     test_wmime_keydown_message();
11787     test_paint_messages();
11788     test_interthread_messages();
11789     test_message_conversion();
11790     test_accelerators();
11791     test_timers();
11792     test_timers_no_wnd();
11793     if (hCBT_hook) test_set_hook();
11794     test_DestroyWindow();
11795     test_DispatchMessage();
11796     test_SendMessageTimeout();
11797     test_edit_messages();
11798     test_quit_message();
11799     test_SetActiveWindow();
11800
11801     if (!pTrackMouseEvent)
11802         win_skip("TrackMouseEvent is not available\n");
11803     else
11804         test_TrackMouseEvent();
11805
11806     test_SetWindowRgn();
11807     test_sys_menu();
11808     test_dialog_messages();
11809     test_nullCallback();
11810     test_dbcs_wm_char();
11811     test_menu_messages();
11812     test_paintingloop();
11813     test_defwinproc();
11814     /* keep it the last test, under Windows it tends to break the tests
11815      * which rely on active/foreground windows being correct.
11816      */
11817     test_SetForegroundWindow();
11818
11819     UnhookWindowsHookEx(hCBT_hook);
11820     if (pUnhookWinEvent && hEvent_hook)
11821     {
11822         ret = pUnhookWinEvent(hEvent_hook);
11823         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11824         SetLastError(0xdeadbeef);
11825         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11826         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11827            GetLastError() == 0xdeadbeef, /* Win9x */
11828            "unexpected error %d\n", GetLastError());
11829     }
11830 }