user32/tests: Add some clipboard viewer tests.
[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|lparam, SIZE_MINIMIZED, 0 },
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|lparam, SIZE_MINIMIZED, 0 },
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|lparam, SIZE_MINIMIZED, 0 },
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|lparam, SIZE_MINIMIZED, 0 },
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|lparam, SIZE_MINIMIZED, 0 },
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 static const struct message WmSetStyleButtonSeq[] =
5213 {
5214     { BM_SETSTYLE, sent },
5215     { WM_APP, sent|wparam|lparam, 0, 0 },
5216     { WM_PAINT, sent },
5217     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5218     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5219     { WM_CTLCOLORBTN, sent|parent },
5220     { 0 }
5221 };
5222 static const struct message WmSetStyleStaticSeq[] =
5223 {
5224     { BM_SETSTYLE, sent },
5225     { WM_APP, sent|wparam|lparam, 0, 0 },
5226     { WM_PAINT, sent },
5227     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5228     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5229     { WM_CTLCOLORSTATIC, sent|parent },
5230     { 0 }
5231 };
5232 static const struct message WmSetStyleUserSeq[] =
5233 {
5234     { BM_SETSTYLE, sent },
5235     { WM_APP, sent|wparam|lparam, 0, 0 },
5236     { WM_PAINT, sent },
5237     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5238     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5239     { WM_CTLCOLORBTN, sent|parent },
5240     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5241     { 0 }
5242 };
5243 static const struct message WmSetStyleOwnerdrawSeq[] =
5244 {
5245     { BM_SETSTYLE, sent },
5246     { WM_APP, sent|wparam|lparam, 0, 0 },
5247     { WM_PAINT, sent },
5248     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5249     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5250     { WM_CTLCOLORBTN, sent|parent },
5251     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5252     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5253     { 0 }
5254 };
5255
5256 static WNDPROC old_button_proc;
5257
5258 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5259 {
5260     static long defwndproc_counter = 0;
5261     LRESULT ret;
5262     struct recvd_message msg;
5263
5264     if (ignore_message( message )) return 0;
5265
5266     switch (message)
5267     {
5268     case WM_SYNCPAINT:
5269         break;
5270     case BM_SETSTATE:
5271         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5272         /* fall through */
5273     default:
5274         msg.hwnd = hwnd;
5275         msg.message = message;
5276         msg.flags = sent|wparam|lparam;
5277         if (defwndproc_counter) msg.flags |= defwinproc;
5278         msg.wParam = wParam;
5279         msg.lParam = lParam;
5280         msg.descr = "button";
5281         add_message(&msg);
5282     }
5283
5284     defwndproc_counter++;
5285     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5286     defwndproc_counter--;
5287
5288     return ret;
5289 }
5290
5291 static void subclass_button(void)
5292 {
5293     WNDCLASSA cls;
5294
5295     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5296
5297     old_button_proc = cls.lpfnWndProc;
5298
5299     cls.hInstance = GetModuleHandle(0);
5300     cls.lpfnWndProc = button_hook_proc;
5301     cls.lpszClassName = "my_button_class";
5302     UnregisterClass(cls.lpszClassName, cls.hInstance);
5303     if (!RegisterClassA(&cls)) assert(0);
5304 }
5305
5306 static void test_button_messages(void)
5307 {
5308     static const struct
5309     {
5310         DWORD style;
5311         DWORD dlg_code;
5312         const struct message *setfocus;
5313         const struct message *killfocus;
5314         const struct message *setstyle;
5315     } button[] = {
5316         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5317           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq },
5318         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5319           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq },
5320         { BS_CHECKBOX, DLGC_BUTTON,
5321           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5322         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5323           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5324         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5325           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5326         { BS_3STATE, DLGC_BUTTON,
5327           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5328         { BS_AUTO3STATE, DLGC_BUTTON,
5329           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5330         { BS_GROUPBOX, DLGC_STATIC,
5331           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5332         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5333           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq },
5334         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5335           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq },
5336         { BS_OWNERDRAW, DLGC_BUTTON,
5337           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq }
5338     };
5339     unsigned int i;
5340     HWND hwnd, parent;
5341     DWORD dlg_code;
5342     HFONT zfont;
5343
5344     /* selection with VK_SPACE should capture button window */
5345     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5346                            0, 0, 50, 14, 0, 0, 0, NULL);
5347     ok(hwnd != 0, "Failed to create button window\n");
5348     ReleaseCapture();
5349     SetFocus(hwnd);
5350     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5351     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5352     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5353     DestroyWindow(hwnd);
5354
5355     subclass_button();
5356
5357     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5358                              100, 100, 200, 200, 0, 0, 0, NULL);
5359     ok(parent != 0, "Failed to create parent window\n");
5360
5361     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5362     {
5363         MSG msg;
5364         DWORD style;
5365
5366         trace("button style %08x\n", button[i].style);
5367
5368         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5369                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5370         ok(hwnd != 0, "Failed to create button window\n");
5371
5372         style = GetWindowLongA(hwnd, GWL_STYLE);
5373         style &= ~(WS_CHILD | BS_NOTIFY);
5374         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5375         if (button[i].style == BS_USERBUTTON)
5376             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5377         else
5378             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5379
5380         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5381         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5382
5383         ShowWindow(hwnd, SW_SHOW);
5384         UpdateWindow(hwnd);
5385         SetFocus(0);
5386         flush_events();
5387         flush_sequence();
5388
5389         log_all_parent_messages++;
5390
5391         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5392         SetFocus(hwnd);
5393         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5394         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5395         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5396
5397         SetFocus(0);
5398         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5399         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5400         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5401
5402         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5403
5404         SendMessage(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5405         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5406         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5407         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5408
5409         style = GetWindowLongA(hwnd, GWL_STYLE);
5410         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5411         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5412         ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5413
5414         log_all_parent_messages--;
5415
5416         DestroyWindow(hwnd);
5417     }
5418
5419     DestroyWindow(parent);
5420
5421     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5422                            0, 0, 50, 14, 0, 0, 0, NULL);
5423     ok(hwnd != 0, "Failed to create button window\n");
5424
5425     SetForegroundWindow(hwnd);
5426     flush_events();
5427
5428     SetActiveWindow(hwnd);
5429     SetFocus(0);
5430     flush_sequence();
5431
5432     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5433     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5434
5435     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5436     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5437
5438     flush_sequence();
5439     zfont = GetStockObject(SYSTEM_FONT);
5440     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5441     UpdateWindow(hwnd);
5442     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5443
5444     DestroyWindow(hwnd);
5445 }
5446
5447 /****************** static message test *************************/
5448 static const struct message WmSetFontStaticSeq[] =
5449 {
5450     { WM_SETFONT, sent },
5451     { WM_PAINT, sent|defwinproc|optional },
5452     { WM_ERASEBKGND, sent|defwinproc|optional },
5453     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5454     { 0 }
5455 };
5456
5457 static WNDPROC old_static_proc;
5458
5459 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5460 {
5461     static long defwndproc_counter = 0;
5462     LRESULT ret;
5463     struct recvd_message msg;
5464
5465     if (ignore_message( message )) return 0;
5466
5467     msg.hwnd = hwnd;
5468     msg.message = message;
5469     msg.flags = sent|wparam|lparam;
5470     if (defwndproc_counter) msg.flags |= defwinproc;
5471     msg.wParam = wParam;
5472     msg.lParam = lParam;
5473     msg.descr = "static";
5474     add_message(&msg);
5475
5476     defwndproc_counter++;
5477     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5478     defwndproc_counter--;
5479
5480     return ret;
5481 }
5482
5483 static void subclass_static(void)
5484 {
5485     WNDCLASSA cls;
5486
5487     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5488
5489     old_static_proc = cls.lpfnWndProc;
5490
5491     cls.hInstance = GetModuleHandle(0);
5492     cls.lpfnWndProc = static_hook_proc;
5493     cls.lpszClassName = "my_static_class";
5494     UnregisterClass(cls.lpszClassName, cls.hInstance);
5495     if (!RegisterClassA(&cls)) assert(0);
5496 }
5497
5498 static void test_static_messages(void)
5499 {
5500     /* FIXME: make as comprehensive as the button message test */
5501     static const struct
5502     {
5503         DWORD style;
5504         DWORD dlg_code;
5505         const struct message *setfont;
5506     } static_ctrl[] = {
5507         { SS_LEFT, DLGC_STATIC,
5508           WmSetFontStaticSeq }
5509     };
5510     unsigned int i;
5511     HWND hwnd;
5512     DWORD dlg_code;
5513
5514     subclass_static();
5515
5516     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5517     {
5518         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5519                                0, 0, 50, 14, 0, 0, 0, NULL);
5520         ok(hwnd != 0, "Failed to create static window\n");
5521
5522         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5523         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5524
5525         ShowWindow(hwnd, SW_SHOW);
5526         UpdateWindow(hwnd);
5527         SetFocus(0);
5528         flush_sequence();
5529
5530         trace("static style %08x\n", static_ctrl[i].style);
5531         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5532         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5533
5534         DestroyWindow(hwnd);
5535     }
5536 }
5537
5538 /****************** ComboBox message test *************************/
5539 #define ID_COMBOBOX 0x000f
5540
5541 static const struct message WmKeyDownComboSeq[] =
5542 {
5543     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5544     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5545     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5546     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5547     { WM_CTLCOLOREDIT, sent|parent },
5548     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5549     { 0 }
5550 };
5551
5552 static WNDPROC old_combobox_proc;
5553
5554 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5555 {
5556     static long defwndproc_counter = 0;
5557     LRESULT ret;
5558     struct recvd_message msg;
5559
5560     /* do not log painting messages */
5561     if (message != WM_PAINT &&
5562         message != WM_NCPAINT &&
5563         message != WM_SYNCPAINT &&
5564         message != WM_ERASEBKGND &&
5565         message != WM_NCHITTEST &&
5566         message != WM_GETTEXT &&
5567         !ignore_message( message ))
5568     {
5569         msg.hwnd = hwnd;
5570         msg.message = message;
5571         msg.flags = sent|wparam|lparam;
5572         if (defwndproc_counter) msg.flags |= defwinproc;
5573         msg.wParam = wParam;
5574         msg.lParam = lParam;
5575         msg.descr = "combo";
5576         add_message(&msg);
5577     }
5578
5579     defwndproc_counter++;
5580     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5581     defwndproc_counter--;
5582
5583     return ret;
5584 }
5585
5586 static void subclass_combobox(void)
5587 {
5588     WNDCLASSA cls;
5589
5590     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5591
5592     old_combobox_proc = cls.lpfnWndProc;
5593
5594     cls.hInstance = GetModuleHandle(0);
5595     cls.lpfnWndProc = combobox_hook_proc;
5596     cls.lpszClassName = "my_combobox_class";
5597     UnregisterClass(cls.lpszClassName, cls.hInstance);
5598     if (!RegisterClassA(&cls)) assert(0);
5599 }
5600
5601 static void test_combobox_messages(void)
5602 {
5603     HWND parent, combo;
5604     LRESULT ret;
5605
5606     subclass_combobox();
5607
5608     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5609                              100, 100, 200, 200, 0, 0, 0, NULL);
5610     ok(parent != 0, "Failed to create parent window\n");
5611     flush_sequence();
5612
5613     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5614                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5615     ok(combo != 0, "Failed to create combobox window\n");
5616
5617     UpdateWindow(combo);
5618
5619     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5620     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5621
5622     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5623     ok(ret == 0, "expected 0, got %ld\n", ret);
5624     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5625     ok(ret == 1, "expected 1, got %ld\n", ret);
5626     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5627     ok(ret == 2, "expected 2, got %ld\n", ret);
5628
5629     SendMessage(combo, CB_SETCURSEL, 0, 0);
5630     SetFocus(combo);
5631     flush_sequence();
5632
5633     log_all_parent_messages++;
5634     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5635     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5636     log_all_parent_messages--;
5637     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5638
5639     DestroyWindow(combo);
5640     DestroyWindow(parent);
5641 }
5642
5643 /****************** WM_IME_KEYDOWN message test *******************/
5644
5645 static const struct message WmImeKeydownMsgSeq_0[] =
5646 {
5647     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5648     { WM_CHAR, wparam, 'A' },
5649     { 0 }
5650 };
5651
5652 static const struct message WmImeKeydownMsgSeq_1[] =
5653 {
5654     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5655     { WM_CHAR,    optional|wparam, VK_RETURN },
5656     { 0 }
5657 };
5658
5659 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5660 {
5661     struct recvd_message msg;
5662
5663     msg.hwnd = hwnd;
5664     msg.message = message;
5665     msg.flags = wparam|lparam;
5666     msg.wParam = wParam;
5667     msg.lParam = lParam;
5668     msg.descr = "wmime_keydown";
5669     add_message(&msg);
5670
5671     return DefWindowProcA(hwnd, message, wParam, lParam);
5672 }
5673
5674 static void register_wmime_keydown_class(void)
5675 {
5676     WNDCLASSA cls;
5677
5678     ZeroMemory(&cls, sizeof(WNDCLASSA));
5679     cls.lpfnWndProc = wmime_keydown_procA;
5680     cls.hInstance = GetModuleHandleA(0);
5681     cls.lpszClassName = "wmime_keydown_class";
5682     if (!RegisterClassA(&cls)) assert(0);
5683 }
5684
5685 static void test_wmime_keydown_message(void)
5686 {
5687     HWND hwnd;
5688     MSG msg;
5689
5690     trace("Message sequences by WM_IME_KEYDOWN\n");
5691
5692     register_wmime_keydown_class();
5693     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5694                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5695                            NULL, NULL, 0);
5696     flush_events();
5697     flush_sequence();
5698
5699     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5700     SendMessage(hwnd, WM_CHAR, 'A', 1);
5701     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5702
5703     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5704     {
5705         TranslateMessage(&msg);
5706         DispatchMessage(&msg);
5707     }
5708     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5709
5710     DestroyWindow(hwnd);
5711 }
5712
5713 /************* painting message test ********************/
5714
5715 void dump_region(HRGN hrgn)
5716 {
5717     DWORD i, size;
5718     RGNDATA *data = NULL;
5719     RECT *rect;
5720
5721     if (!hrgn)
5722     {
5723         printf( "null region\n" );
5724         return;
5725     }
5726     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5727     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5728     GetRegionData( hrgn, size, data );
5729     printf("%d rects:", data->rdh.nCount );
5730     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5731         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5732     printf("\n");
5733     HeapFree( GetProcessHeap(), 0, data );
5734 }
5735
5736 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5737 {
5738     INT ret;
5739     RECT r1, r2;
5740     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5741     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5742
5743     ret = GetUpdateRgn( hwnd, update, FALSE );
5744     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5745     if (ret == NULLREGION)
5746     {
5747         ok( !hrgn, "Update region shouldn't be empty\n" );
5748     }
5749     else
5750     {
5751         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5752         {
5753             ok( 0, "Regions are different\n" );
5754             if (winetest_debug > 0)
5755             {
5756                 printf( "Update region: " );
5757                 dump_region( update );
5758                 printf( "Wanted region: " );
5759                 dump_region( hrgn );
5760             }
5761         }
5762     }
5763     GetRgnBox( update, &r1 );
5764     GetUpdateRect( hwnd, &r2, FALSE );
5765     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5766         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5767         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5768
5769     DeleteObject( tmp );
5770     DeleteObject( update );
5771 }
5772
5773 static const struct message WmInvalidateRgn[] = {
5774     { WM_NCPAINT, sent },
5775     { WM_GETTEXT, sent|defwinproc|optional },
5776     { 0 }
5777 };
5778
5779 static const struct message WmGetUpdateRect[] = {
5780     { WM_NCPAINT, sent },
5781     { WM_GETTEXT, sent|defwinproc|optional },
5782     { WM_PAINT, sent },
5783     { 0 }
5784 };
5785
5786 static const struct message WmInvalidateFull[] = {
5787     { WM_NCPAINT, sent|wparam, 1 },
5788     { WM_GETTEXT, sent|defwinproc|optional },
5789     { 0 }
5790 };
5791
5792 static const struct message WmInvalidateErase[] = {
5793     { WM_NCPAINT, sent|wparam, 1 },
5794     { WM_GETTEXT, sent|defwinproc|optional },
5795     { WM_ERASEBKGND, sent },
5796     { 0 }
5797 };
5798
5799 static const struct message WmInvalidatePaint[] = {
5800     { WM_PAINT, sent },
5801     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5802     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5803     { 0 }
5804 };
5805
5806 static const struct message WmInvalidateErasePaint[] = {
5807     { WM_PAINT, sent },
5808     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5809     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5810     { WM_ERASEBKGND, sent|beginpaint|optional },
5811     { 0 }
5812 };
5813
5814 static const struct message WmInvalidateErasePaint2[] = {
5815     { WM_PAINT, sent },
5816     { WM_NCPAINT, sent|beginpaint },
5817     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5818     { WM_ERASEBKGND, sent|beginpaint|optional },
5819     { 0 }
5820 };
5821
5822 static const struct message WmErase[] = {
5823     { WM_ERASEBKGND, sent },
5824     { 0 }
5825 };
5826
5827 static const struct message WmPaint[] = {
5828     { WM_PAINT, sent },
5829     { 0 }
5830 };
5831
5832 static const struct message WmParentOnlyPaint[] = {
5833     { WM_PAINT, sent|parent },
5834     { 0 }
5835 };
5836
5837 static const struct message WmInvalidateParent[] = {
5838     { WM_NCPAINT, sent|parent },
5839     { WM_GETTEXT, sent|defwinproc|parent|optional },
5840     { WM_ERASEBKGND, sent|parent },
5841     { 0 }
5842 };
5843
5844 static const struct message WmInvalidateParentChild[] = {
5845     { WM_NCPAINT, sent|parent },
5846     { WM_GETTEXT, sent|defwinproc|parent|optional },
5847     { WM_ERASEBKGND, sent|parent },
5848     { WM_NCPAINT, sent },
5849     { WM_GETTEXT, sent|defwinproc|optional },
5850     { WM_ERASEBKGND, sent },
5851     { 0 }
5852 };
5853
5854 static const struct message WmInvalidateParentChild2[] = {
5855     { WM_ERASEBKGND, sent|parent },
5856     { WM_NCPAINT, sent },
5857     { WM_GETTEXT, sent|defwinproc|optional },
5858     { WM_ERASEBKGND, sent },
5859     { 0 }
5860 };
5861
5862 static const struct message WmParentPaint[] = {
5863     { WM_PAINT, sent|parent },
5864     { WM_PAINT, sent },
5865     { 0 }
5866 };
5867
5868 static const struct message WmParentPaintNc[] = {
5869     { WM_PAINT, sent|parent },
5870     { WM_PAINT, sent },
5871     { WM_NCPAINT, sent|beginpaint },
5872     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5873     { WM_ERASEBKGND, sent|beginpaint|optional },
5874     { 0 }
5875 };
5876
5877 static const struct message WmChildPaintNc[] = {
5878     { WM_PAINT, sent },
5879     { WM_NCPAINT, sent|beginpaint },
5880     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5881     { WM_ERASEBKGND, sent|beginpaint|optional },
5882     { 0 }
5883 };
5884
5885 static const struct message WmParentErasePaint[] = {
5886     { WM_PAINT, sent|parent },
5887     { WM_NCPAINT, sent|parent|beginpaint },
5888     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5889     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
5890     { WM_PAINT, sent },
5891     { WM_NCPAINT, sent|beginpaint },
5892     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5893     { WM_ERASEBKGND, sent|beginpaint|optional },
5894     { 0 }
5895 };
5896
5897 static const struct message WmParentOnlyNcPaint[] = {
5898     { WM_PAINT, sent|parent },
5899     { WM_NCPAINT, sent|parent|beginpaint },
5900     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5901     { 0 }
5902 };
5903
5904 static const struct message WmSetParentStyle[] = {
5905     { WM_STYLECHANGING, sent|parent },
5906     { WM_STYLECHANGED, sent|parent },
5907     { 0 }
5908 };
5909
5910 static void test_paint_messages(void)
5911 {
5912     BOOL ret;
5913     RECT rect;
5914     POINT pt;
5915     MSG msg;
5916     HWND hparent, hchild;
5917     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5918     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5919     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5920                                 100, 100, 200, 200, 0, 0, 0, NULL);
5921     ok (hwnd != 0, "Failed to create overlapped window\n");
5922
5923     ShowWindow( hwnd, SW_SHOW );
5924     UpdateWindow( hwnd );
5925     flush_events();
5926     flush_sequence();
5927
5928     check_update_rgn( hwnd, 0 );
5929     SetRectRgn( hrgn, 10, 10, 20, 20 );
5930     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5931     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5932     check_update_rgn( hwnd, hrgn );
5933     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5934     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5935     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5936     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5937     check_update_rgn( hwnd, hrgn );
5938     /* validate everything */
5939     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5940     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5941     check_update_rgn( hwnd, 0 );
5942
5943     /* test empty region */
5944     SetRectRgn( hrgn, 10, 10, 10, 15 );
5945     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5946     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5947     check_update_rgn( hwnd, 0 );
5948     /* test empty rect */
5949     SetRect( &rect, 10, 10, 10, 15 );
5950     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5951     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5952     check_update_rgn( hwnd, 0 );
5953
5954     /* flush pending messages */
5955     flush_events();
5956     flush_sequence();
5957
5958     GetClientRect( hwnd, &rect );
5959     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5960     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5961      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5962      */
5963     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5964     SetRectEmpty( &rect );
5965     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5966     check_update_rgn( hwnd, hrgn );
5967     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5968     flush_events();
5969     ok_sequence( WmPaint, "Paint", FALSE );
5970     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5971     check_update_rgn( hwnd, 0 );
5972
5973     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5974      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5975      */
5976     trace("testing ValidateRect(0, NULL)\n");
5977     SetRectEmpty( &rect );
5978     if (ValidateRect(0, &rect))  /* not supported on Win9x */
5979     {
5980         check_update_rgn( hwnd, hrgn );
5981         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5982         flush_events();
5983         ok_sequence( WmPaint, "Paint", FALSE );
5984         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5985         check_update_rgn( hwnd, 0 );
5986     }
5987
5988     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5989     SetLastError(0xdeadbeef);
5990     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5991     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5992        "wrong error code %d\n", GetLastError());
5993     check_update_rgn( hwnd, 0 );
5994     flush_events();
5995     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5996
5997     trace("testing ValidateRgn(0, NULL)\n");
5998     SetLastError(0xdeadbeef);
5999     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6000     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6001        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6002        "wrong error code %d\n", GetLastError());
6003     check_update_rgn( hwnd, 0 );
6004     flush_events();
6005     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6006
6007     /* now with frame */
6008     SetRectRgn( hrgn, -5, -5, 20, 20 );
6009
6010     /* flush pending messages */
6011     flush_events();
6012     flush_sequence();
6013     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6014     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6015
6016     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
6017     check_update_rgn( hwnd, hrgn );
6018
6019     flush_sequence();
6020     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6021     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6022
6023     flush_sequence();
6024     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6025     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6026
6027     GetClientRect( hwnd, &rect );
6028     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6029     check_update_rgn( hwnd, hrgn );
6030
6031     flush_sequence();
6032     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6033     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6034
6035     flush_sequence();
6036     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6037     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6038     check_update_rgn( hwnd, 0 );
6039
6040     flush_sequence();
6041     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6042     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6043     check_update_rgn( hwnd, 0 );
6044
6045     flush_sequence();
6046     SetRectRgn( hrgn, 0, 0, 100, 100 );
6047     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6048     SetRectRgn( hrgn, 0, 0, 50, 100 );
6049     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6050     SetRectRgn( hrgn, 50, 0, 100, 100 );
6051     check_update_rgn( hwnd, hrgn );
6052     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6053     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
6054     check_update_rgn( hwnd, 0 );
6055
6056     flush_sequence();
6057     SetRectRgn( hrgn, 0, 0, 100, 100 );
6058     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6059     SetRectRgn( hrgn, 0, 0, 100, 50 );
6060     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6061     ok_sequence( WmErase, "Erase", FALSE );
6062     SetRectRgn( hrgn, 0, 50, 100, 100 );
6063     check_update_rgn( hwnd, hrgn );
6064
6065     flush_sequence();
6066     SetRectRgn( hrgn, 0, 0, 100, 100 );
6067     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6068     SetRectRgn( hrgn, 0, 0, 50, 50 );
6069     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6070     ok_sequence( WmPaint, "Paint", FALSE );
6071
6072     flush_sequence();
6073     SetRectRgn( hrgn, -4, -4, -2, -2 );
6074     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6075     SetRectRgn( hrgn, -200, -200, -198, -198 );
6076     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6077     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6078
6079     flush_sequence();
6080     SetRectRgn( hrgn, -4, -4, -2, -2 );
6081     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6082     SetRectRgn( hrgn, -4, -4, -3, -3 );
6083     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6084     SetRectRgn( hrgn, 0, 0, 1, 1 );
6085     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6086     ok_sequence( WmPaint, "Paint", FALSE );
6087
6088     flush_sequence();
6089     SetRectRgn( hrgn, -4, -4, -1, -1 );
6090     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6091     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6092     /* make sure no WM_PAINT was generated */
6093     flush_events();
6094     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6095
6096     flush_sequence();
6097     SetRectRgn( hrgn, -4, -4, -1, -1 );
6098     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6099     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6100     {
6101         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6102         {
6103             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6104             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6105             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6106             ret = GetUpdateRect( hwnd, &rect, FALSE );
6107             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6108             /* this will send WM_NCPAINT and validate the non client area */
6109             ret = GetUpdateRect( hwnd, &rect, TRUE );
6110             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6111         }
6112         DispatchMessage( &msg );
6113     }
6114     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6115
6116     DestroyWindow( hwnd );
6117
6118     /* now test with a child window */
6119
6120     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6121                               100, 100, 200, 200, 0, 0, 0, NULL);
6122     ok (hparent != 0, "Failed to create parent window\n");
6123
6124     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6125                            10, 10, 100, 100, hparent, 0, 0, NULL);
6126     ok (hchild != 0, "Failed to create child window\n");
6127
6128     ShowWindow( hparent, SW_SHOW );
6129     UpdateWindow( hparent );
6130     UpdateWindow( hchild );
6131     flush_events();
6132     flush_sequence();
6133     log_all_parent_messages++;
6134
6135     SetRect( &rect, 0, 0, 50, 50 );
6136     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6137     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6138     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6139
6140     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6141     pt.x = pt.y = 0;
6142     MapWindowPoints( hchild, hparent, &pt, 1 );
6143     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6144     check_update_rgn( hchild, hrgn );
6145     SetRectRgn( hrgn, 0, 0, 50, 50 );
6146     check_update_rgn( hparent, hrgn );
6147     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6148     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6149     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6150     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6151
6152     flush_events();
6153     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6154
6155     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6156     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6157     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6158     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6159     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6160
6161     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6162     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6163     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6164
6165     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6166     flush_sequence();
6167     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6168     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6169     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6170
6171     /* flush all paint messages */
6172     flush_events();
6173     flush_sequence();
6174
6175     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6176     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6177     SetRectRgn( hrgn, 0, 0, 50, 50 );
6178     check_update_rgn( hparent, hrgn );
6179     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6180     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6181     SetRectRgn( hrgn, 0, 0, 50, 50 );
6182     check_update_rgn( hparent, hrgn );
6183
6184     /* flush all paint messages */
6185     flush_events();
6186     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6187     flush_sequence();
6188
6189     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6190     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6191     SetRectRgn( hrgn, 0, 0, 50, 50 );
6192     check_update_rgn( hparent, hrgn );
6193     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6194     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6195     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6196     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6197     check_update_rgn( hparent, hrgn );
6198     /* flush all paint messages */
6199     flush_events();
6200     flush_sequence();
6201
6202     /* same as above but parent gets completely validated */
6203     SetRect( &rect, 20, 20, 30, 30 );
6204     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6205     SetRectRgn( hrgn, 20, 20, 30, 30 );
6206     check_update_rgn( hparent, hrgn );
6207     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6208     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6209     check_update_rgn( hparent, 0 );  /* no update region */
6210     flush_events();
6211     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6212
6213     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6214     flush_sequence();
6215     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6216     SetRectRgn( hrgn, 20, 20, 30, 30 );
6217     check_update_rgn( hparent, hrgn );
6218     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6219     SetRectRgn( hrgn, 20, 20, 30, 30 );
6220     check_update_rgn( hparent, hrgn );
6221
6222     /* same as above but normal WM_PAINT doesn't validate parent */
6223     flush_sequence();
6224     SetRect( &rect, 20, 20, 30, 30 );
6225     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6226     SetRectRgn( hrgn, 20, 20, 30, 30 );
6227     check_update_rgn( hparent, hrgn );
6228     /* no WM_PAINT in child while parent still pending */
6229     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6230     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6231     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6232     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6233
6234     flush_sequence();
6235     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6236     /* no WM_PAINT in child while parent still pending */
6237     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6238     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6239     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6240     /* now that parent is valid child should get WM_PAINT */
6241     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6242     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6243     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6244     ok_sequence( WmEmptySeq, "No other message", FALSE );
6245
6246     /* same thing with WS_CLIPCHILDREN in parent */
6247     flush_sequence();
6248     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6249     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6250     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6251     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6252     ok_sequence( WmEmptySeq, "No message", FALSE );
6253     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6254     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6255
6256     flush_sequence();
6257     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6258     SetRectRgn( hrgn, 20, 20, 30, 30 );
6259     check_update_rgn( hparent, hrgn );
6260     /* no WM_PAINT in child while parent still pending */
6261     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6262     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6263     /* WM_PAINT in parent first */
6264     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6265     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6266
6267     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6268     flush_sequence();
6269     SetRect( &rect, 0, 0, 30, 30 );
6270     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6271     SetRectRgn( hrgn, 0, 0, 30, 30 );
6272     check_update_rgn( hparent, hrgn );
6273     flush_events();
6274     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6275
6276     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6277     flush_sequence();
6278     SetRect( &rect, -10, 0, 30, 30 );
6279     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6280     SetRect( &rect, 0, 0, 20, 20 );
6281     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6282     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6283     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6284
6285     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6286     flush_sequence();
6287     SetRect( &rect, -10, 0, 30, 30 );
6288     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6289     SetRect( &rect, 0, 0, 100, 100 );
6290     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6291     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6292     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6293     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6294     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6295
6296     /* test RDW_INTERNALPAINT behavior */
6297
6298     flush_sequence();
6299     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6300     flush_events();
6301     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6302
6303     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6304     flush_events();
6305     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6306
6307     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6308     flush_events();
6309     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6310
6311     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6312     UpdateWindow( hparent );
6313     flush_events();
6314     flush_sequence();
6315     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6316     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6317     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6318                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6319     flush_events();
6320     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6321
6322     UpdateWindow( hparent );
6323     flush_events();
6324     flush_sequence();
6325     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6326     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6327     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6328                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6329     flush_events();
6330     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6331
6332     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6333     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6334     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6335     flush_events();
6336     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6337
6338     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6339     UpdateWindow( hparent );
6340     flush_events();
6341     flush_sequence();
6342     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6343     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6344     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6345                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6346     flush_events();
6347     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6348
6349     UpdateWindow( hparent );
6350     flush_events();
6351     flush_sequence();
6352     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6353     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6354     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6355                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6356     flush_events();
6357     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6358
6359     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6360     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6361
6362     UpdateWindow( hparent );
6363     flush_events();
6364     flush_sequence();
6365     trace("testing SetWindowPos(-10000, -10000) on child\n");
6366     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6367     check_update_rgn( hchild, 0 );
6368     flush_events();
6369
6370 #if 0 /* this one doesn't pass under Wine yet */
6371     UpdateWindow( hparent );
6372     flush_events();
6373     flush_sequence();
6374     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6375     ShowWindow( hchild, SW_MINIMIZE );
6376     check_update_rgn( hchild, 0 );
6377     flush_events();
6378 #endif
6379
6380     UpdateWindow( hparent );
6381     flush_events();
6382     flush_sequence();
6383     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6384     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6385     check_update_rgn( hparent, 0 );
6386     flush_events();
6387
6388     log_all_parent_messages--;
6389     DestroyWindow( hparent );
6390     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6391
6392     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6393
6394     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6395                               100, 100, 200, 200, 0, 0, 0, NULL);
6396     ok (hparent != 0, "Failed to create parent window\n");
6397
6398     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6399                            10, 10, 100, 100, hparent, 0, 0, NULL);
6400     ok (hchild != 0, "Failed to create child window\n");
6401
6402     ShowWindow( hparent, SW_SHOW );
6403     UpdateWindow( hparent );
6404     UpdateWindow( hchild );
6405     flush_events();
6406     flush_sequence();
6407
6408     /* moving child outside of parent boundaries changes update region */
6409     SetRect( &rect, 0, 0, 40, 40 );
6410     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6411     SetRectRgn( hrgn, 0, 0, 40, 40 );
6412     check_update_rgn( hchild, hrgn );
6413     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6414     SetRectRgn( hrgn, 10, 0, 40, 40 );
6415     check_update_rgn( hchild, hrgn );
6416     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6417     SetRectRgn( hrgn, 10, 10, 40, 40 );
6418     check_update_rgn( hchild, hrgn );
6419
6420     /* moving parent off-screen does too */
6421     SetRect( &rect, 0, 0, 100, 100 );
6422     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6423     SetRectRgn( hrgn, 0, 0, 100, 100 );
6424     check_update_rgn( hparent, hrgn );
6425     SetRectRgn( hrgn, 10, 10, 40, 40 );
6426     check_update_rgn( hchild, hrgn );
6427     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6428     SetRectRgn( hrgn, 20, 20, 100, 100 );
6429     check_update_rgn( hparent, hrgn );
6430     SetRectRgn( hrgn, 30, 30, 40, 40 );
6431     check_update_rgn( hchild, hrgn );
6432
6433     /* invalidated region is cropped by the parent rects */
6434     SetRect( &rect, 0, 0, 50, 50 );
6435     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6436     SetRectRgn( hrgn, 30, 30, 50, 50 );
6437     check_update_rgn( hchild, hrgn );
6438
6439     DestroyWindow( hparent );
6440     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6441     flush_sequence();
6442
6443     DeleteObject( hrgn );
6444     DeleteObject( hrgn2 );
6445 }
6446
6447 struct wnd_event
6448 {
6449     HWND hwnd;
6450     HANDLE grand_child;
6451     HANDLE start_event;
6452     HANDLE stop_event;
6453 };
6454
6455 static DWORD WINAPI thread_proc(void *param)
6456 {
6457     MSG msg;
6458     struct wnd_event *wnd_event = param;
6459
6460     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6461                                       100, 100, 200, 200, 0, 0, 0, NULL);
6462     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6463
6464     SetEvent(wnd_event->start_event);
6465
6466     while (GetMessage(&msg, 0, 0, 0))
6467     {
6468         TranslateMessage(&msg);
6469         DispatchMessage(&msg);
6470     }
6471
6472     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6473
6474     return 0;
6475 }
6476
6477 static DWORD CALLBACK create_grand_child_thread( void *param )
6478 {
6479     struct wnd_event *wnd_event = param;
6480     HWND hchild;
6481     MSG msg;
6482
6483     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6484                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6485     ok (hchild != 0, "Failed to create child window\n");
6486     flush_events();
6487     flush_sequence();
6488     SetEvent( wnd_event->start_event );
6489
6490     for (;;)
6491     {
6492         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6493         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6494         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6495     }
6496     return 0;
6497 }
6498
6499 static DWORD CALLBACK create_child_thread( void *param )
6500 {
6501     struct wnd_event *wnd_event = param;
6502     struct wnd_event child_event;
6503     DWORD ret, tid;
6504     MSG msg;
6505
6506     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6507                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6508     ok (child_event.hwnd != 0, "Failed to create child window\n");
6509     SetFocus( child_event.hwnd );
6510     flush_events();
6511     flush_sequence();
6512     child_event.start_event = wnd_event->start_event;
6513     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6514     for (;;)
6515     {
6516         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6517         if (ret != 1) break;
6518         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6519     }
6520     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6521     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6522     return 0;
6523 }
6524
6525 static void test_interthread_messages(void)
6526 {
6527     HANDLE hThread;
6528     DWORD tid;
6529     WNDPROC proc;
6530     MSG msg;
6531     char buf[256];
6532     int len, expected_len;
6533     struct wnd_event wnd_event;
6534     BOOL ret;
6535
6536     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6537     if (!wnd_event.start_event)
6538     {
6539         win_skip("skipping interthread message test under win9x\n");
6540         return;
6541     }
6542
6543     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6544     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6545
6546     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6547
6548     CloseHandle(wnd_event.start_event);
6549
6550     SetLastError(0xdeadbeef);
6551     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6552     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6553        "wrong error code %d\n", GetLastError());
6554
6555     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6556     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6557
6558     expected_len = lstrlenA("window caption text");
6559     memset(buf, 0, sizeof(buf));
6560     SetLastError(0xdeadbeef);
6561     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6562     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6563     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6564
6565     msg.hwnd = wnd_event.hwnd;
6566     msg.message = WM_GETTEXT;
6567     msg.wParam = sizeof(buf);
6568     msg.lParam = (LPARAM)buf;
6569     memset(buf, 0, sizeof(buf));
6570     SetLastError(0xdeadbeef);
6571     len = DispatchMessageA(&msg);
6572     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6573        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6574
6575     /* the following test causes an exception in user.exe under win9x */
6576     msg.hwnd = wnd_event.hwnd;
6577     msg.message = WM_TIMER;
6578     msg.wParam = 0;
6579     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6580     SetLastError(0xdeadbeef);
6581     len = DispatchMessageA(&msg);
6582     ok(!len && GetLastError() == 0xdeadbeef,
6583        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6584
6585     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6586     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6587
6588     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6589     CloseHandle(hThread);
6590
6591     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6592
6593     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6594                               100, 100, 200, 200, 0, 0, 0, NULL);
6595     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6596     flush_sequence();
6597     log_all_parent_messages++;
6598     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6599     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6600     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6601     for (;;)
6602     {
6603         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6604         if (ret != 1) break;
6605         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6606     }
6607     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6608     /* now wait for the thread without processing messages; this shouldn't deadlock */
6609     SetEvent( wnd_event.stop_event );
6610     ret = WaitForSingleObject( hThread, 5000 );
6611     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6612     CloseHandle( hThread );
6613
6614     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6615     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6616     CloseHandle( wnd_event.grand_child );
6617
6618     CloseHandle( wnd_event.start_event );
6619     CloseHandle( wnd_event.stop_event );
6620     flush_events();
6621     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6622     log_all_parent_messages--;
6623     DestroyWindow( wnd_event.hwnd );
6624 }
6625
6626
6627 static const struct message WmVkN[] = {
6628     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6629     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6630     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6631     { WM_CHAR, wparam|lparam, 'n', 1 },
6632     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6633     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6634     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6635     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6636     { 0 }
6637 };
6638 static const struct message WmShiftVkN[] = {
6639     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6640     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6641     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6642     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6643     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6644     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6645     { WM_CHAR, wparam|lparam, 'N', 1 },
6646     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6647     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6648     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6649     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6650     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6651     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6652     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6653     { 0 }
6654 };
6655 static const struct message WmCtrlVkN[] = {
6656     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6657     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6658     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6659     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6660     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6661     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6662     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6663     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6664     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6665     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6666     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6667     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6668     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6669     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6670     { 0 }
6671 };
6672 static const struct message WmCtrlVkN_2[] = {
6673     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6674     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6675     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6676     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6677     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6678     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6679     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6680     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6681     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6682     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6683     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6684     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6685     { 0 }
6686 };
6687 static const struct message WmAltVkN[] = {
6688     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6689     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6690     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6691     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6692     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6693     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6694     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6695     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6696     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6697     { HCBT_SYSCOMMAND, hook },
6698     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6699     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6700     { 0x00AE, sent|defwinproc|optional }, /* XP */
6701     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6702     { WM_INITMENU, sent|defwinproc },
6703     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6704     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6705     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6706     { WM_CAPTURECHANGED, sent|defwinproc },
6707     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6708     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6709     { WM_EXITMENULOOP, sent|defwinproc },
6710     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6711     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6712     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6713     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6714     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6715     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6716     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6717     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6718     { 0 }
6719 };
6720 static const struct message WmAltVkN_2[] = {
6721     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6722     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6723     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6724     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6725     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6726     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6727     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6728     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6729     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6730     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6731     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6732     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6733     { 0 }
6734 };
6735 static const struct message WmCtrlAltVkN[] = {
6736     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6737     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6738     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6739     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6740     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6741     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6742     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6743     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6744     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6745     { WM_CHAR, optional },
6746     { WM_CHAR, sent|optional },
6747     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6748     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6749     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6750     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6751     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6752     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6753     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6754     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6755     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6756     { 0 }
6757 };
6758 static const struct message WmCtrlShiftVkN[] = {
6759     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6760     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6761     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6762     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6763     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6764     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6765     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6766     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6767     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6768     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6769     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6770     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6771     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6772     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6773     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6774     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6775     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6776     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6777     { 0 }
6778 };
6779 static const struct message WmCtrlAltShiftVkN[] = {
6780     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6781     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6782     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6783     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6784     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6785     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6786     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6787     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6788     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6789     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6790     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6791     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6792     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6793     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6794     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6795     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6796     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6797     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6798     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6799     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6800     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6801     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6802     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6803     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6804     { 0 }
6805 };
6806 static const struct message WmAltPressRelease[] = {
6807     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6808     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6809     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6810     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6811     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6812     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6813     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6814     { HCBT_SYSCOMMAND, hook },
6815     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6816     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6817     { WM_INITMENU, sent|defwinproc },
6818     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6819     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6820     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6821
6822     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6823
6824     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6825     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6826     { WM_CAPTURECHANGED, sent|defwinproc },
6827     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6828     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6829     { WM_EXITMENULOOP, sent|defwinproc },
6830     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6831     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6832     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6833     { 0 }
6834 };
6835 static const struct message WmShiftMouseButton[] = {
6836     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6837     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6838     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6839     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6840     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6841     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
6842     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
6843     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
6844     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
6845     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6846     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6847     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6848     { 0 }
6849 };
6850 static const struct message WmF1Seq[] = {
6851     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6852     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6853     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6854     { WM_KEYF1, wparam|lparam, 0, 0 },
6855     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6856     { WM_HELP, sent|defwinproc },
6857     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6858     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6859     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6860     { 0 }
6861 };
6862 static const struct message WmVkAppsSeq[] = {
6863     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6864     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6865     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6866     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6867     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6868     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6869     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6870     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6871     { 0 }
6872 };
6873
6874 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6875 {
6876     MSG msg;
6877
6878     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6879     {
6880         struct recvd_message log_msg;
6881
6882         /* ignore some unwanted messages */
6883         if (msg.message == WM_MOUSEMOVE ||
6884             msg.message == WM_TIMER ||
6885             ignore_message( msg.message ))
6886             continue;
6887
6888         log_msg.hwnd = msg.hwnd;
6889         log_msg.message = msg.message;
6890         log_msg.flags = wparam|lparam;
6891         log_msg.wParam = msg.wParam;
6892         log_msg.lParam = msg.lParam;
6893         log_msg.descr = "accel";
6894         add_message(&log_msg);
6895
6896         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6897         {
6898             TranslateMessage(&msg);
6899             DispatchMessage(&msg);
6900         }
6901     }
6902 }
6903
6904 static void test_accelerators(void)
6905 {
6906     RECT rc;
6907     POINT pt;
6908     SHORT state;
6909     HACCEL hAccel;
6910     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6911                                 100, 100, 200, 200, 0, 0, 0, NULL);
6912     BOOL ret;
6913
6914     assert(hwnd != 0);
6915     UpdateWindow(hwnd);
6916     flush_events();
6917     flush_sequence();
6918
6919     SetFocus(hwnd);
6920     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6921
6922     state = GetKeyState(VK_SHIFT);
6923     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6924     state = GetKeyState(VK_CAPITAL);
6925     ok(state == 0, "wrong CapsLock state %04x\n", state);
6926
6927     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6928     assert(hAccel != 0);
6929
6930     flush_events();
6931     pump_msg_loop(hwnd, 0);
6932     flush_sequence();
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     if (!sequence_cnt)  /* we didn't get any message */
6940     {
6941         skip( "queuing key events not supported\n" );
6942         goto done;
6943     }
6944     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6945
6946     trace("testing Shift+VK_N press/release\n");
6947     flush_sequence();
6948     keybd_event(VK_SHIFT, 0, 0, 0);
6949     keybd_event('N', 0, 0, 0);
6950     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6951     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6952     pump_msg_loop(hwnd, hAccel);
6953     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6954
6955     trace("testing Ctrl+VK_N press/release\n");
6956     flush_sequence();
6957     keybd_event(VK_CONTROL, 0, 0, 0);
6958     keybd_event('N', 0, 0, 0);
6959     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6960     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6961     pump_msg_loop(hwnd, hAccel);
6962     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6963
6964     trace("testing Alt+VK_N press/release\n");
6965     flush_sequence();
6966     keybd_event(VK_MENU, 0, 0, 0);
6967     keybd_event('N', 0, 0, 0);
6968     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6969     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6970     pump_msg_loop(hwnd, hAccel);
6971     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6972
6973     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6974     flush_sequence();
6975     keybd_event(VK_CONTROL, 0, 0, 0);
6976     keybd_event(VK_MENU, 0, 0, 0);
6977     keybd_event('N', 0, 0, 0);
6978     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6979     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6980     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6981     pump_msg_loop(hwnd, hAccel);
6982     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6983
6984     ret = DestroyAcceleratorTable(hAccel);
6985     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6986
6987     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6988     assert(hAccel != 0);
6989
6990     trace("testing VK_N press/release\n");
6991     flush_sequence();
6992     keybd_event('N', 0, 0, 0);
6993     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6994     pump_msg_loop(hwnd, hAccel);
6995     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6996
6997     trace("testing Shift+VK_N press/release\n");
6998     flush_sequence();
6999     keybd_event(VK_SHIFT, 0, 0, 0);
7000     keybd_event('N', 0, 0, 0);
7001     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7002     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7003     pump_msg_loop(hwnd, hAccel);
7004     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7005
7006     trace("testing Ctrl+VK_N press/release 2\n");
7007     flush_sequence();
7008     keybd_event(VK_CONTROL, 0, 0, 0);
7009     keybd_event('N', 0, 0, 0);
7010     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7011     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7012     pump_msg_loop(hwnd, hAccel);
7013     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7014
7015     trace("testing Alt+VK_N press/release 2\n");
7016     flush_sequence();
7017     keybd_event(VK_MENU, 0, 0, 0);
7018     keybd_event('N', 0, 0, 0);
7019     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7020     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7021     pump_msg_loop(hwnd, hAccel);
7022     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7023
7024     trace("testing Ctrl+Alt+VK_N press/release 2\n");
7025     flush_sequence();
7026     keybd_event(VK_CONTROL, 0, 0, 0);
7027     keybd_event(VK_MENU, 0, 0, 0);
7028     keybd_event('N', 0, 0, 0);
7029     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7030     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7031     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7032     pump_msg_loop(hwnd, hAccel);
7033     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7034
7035     trace("testing Ctrl+Shift+VK_N press/release\n");
7036     flush_sequence();
7037     keybd_event(VK_CONTROL, 0, 0, 0);
7038     keybd_event(VK_SHIFT, 0, 0, 0);
7039     keybd_event('N', 0, 0, 0);
7040     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7041     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7042     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7043     pump_msg_loop(hwnd, hAccel);
7044     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7045
7046     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7047     flush_sequence();
7048     keybd_event(VK_CONTROL, 0, 0, 0);
7049     keybd_event(VK_MENU, 0, 0, 0);
7050     keybd_event(VK_SHIFT, 0, 0, 0);
7051     keybd_event('N', 0, 0, 0);
7052     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7053     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7054     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7055     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7056     pump_msg_loop(hwnd, hAccel);
7057     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7058
7059     ret = DestroyAcceleratorTable(hAccel);
7060     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7061     hAccel = 0;
7062
7063     trace("testing Alt press/release\n");
7064     flush_sequence();
7065     keybd_event(VK_MENU, 0, 0, 0);
7066     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7067     keybd_event(VK_MENU, 0, 0, 0);
7068     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7069     pump_msg_loop(hwnd, 0);
7070     /* this test doesn't pass in Wine for managed windows */
7071     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7072
7073     trace("testing VK_F1 press/release\n");
7074     keybd_event(VK_F1, 0, 0, 0);
7075     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7076     pump_msg_loop(hwnd, 0);
7077     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7078
7079     trace("testing VK_APPS press/release\n");
7080     keybd_event(VK_APPS, 0, 0, 0);
7081     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7082     pump_msg_loop(hwnd, 0);
7083     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7084
7085     trace("testing Shift+MouseButton press/release\n");
7086     /* first, move mouse pointer inside of the window client area */
7087     GetClientRect(hwnd, &rc);
7088     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7089     rc.left += (rc.right - rc.left)/2;
7090     rc.top += (rc.bottom - rc.top)/2;
7091     SetCursorPos(rc.left, rc.top);
7092     SetActiveWindow(hwnd);
7093
7094     flush_events();
7095     flush_sequence();
7096     GetCursorPos(&pt);
7097     if (pt.x == rc.left && pt.y == rc.top)
7098     {
7099         int i;
7100         keybd_event(VK_SHIFT, 0, 0, 0);
7101         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7102         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7103         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7104         pump_msg_loop(hwnd, 0);
7105         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7106         if (i < sequence_cnt)
7107             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7108         else
7109             skip( "Shift+MouseButton event didn't get to the window\n" );
7110     }
7111
7112 done:
7113     if (hAccel) DestroyAcceleratorTable(hAccel);
7114     DestroyWindow(hwnd);
7115 }
7116
7117 /************* window procedures ********************/
7118
7119 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
7120                              WPARAM wParam, LPARAM lParam)
7121 {
7122     static LONG defwndproc_counter = 0;
7123     static LONG beginpaint_counter = 0;
7124     LRESULT ret;
7125     struct recvd_message msg;
7126
7127     if (ignore_message( message )) return 0;
7128
7129     switch (message)
7130     {
7131         case WM_ENABLE:
7132         {
7133             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7134             ok((BOOL)wParam == !(style & WS_DISABLED),
7135                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7136             break;
7137         }
7138
7139         case WM_CAPTURECHANGED:
7140             if (test_DestroyWindow_flag)
7141             {
7142                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7143                 if (style & WS_CHILD)
7144                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7145                 else if (style & WS_POPUP)
7146                     lParam = WND_POPUP_ID;
7147                 else
7148                     lParam = WND_PARENT_ID;
7149             }
7150             break;
7151
7152         case WM_NCDESTROY:
7153         {
7154             HWND capture;
7155
7156             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7157             capture = GetCapture();
7158             if (capture)
7159             {
7160                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7161                 trace("current capture %p, releasing...\n", capture);
7162                 ReleaseCapture();
7163             }
7164         }
7165         /* fall through */
7166         case WM_DESTROY:
7167             if (pGetAncestor)
7168                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7169             if (test_DestroyWindow_flag)
7170             {
7171                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7172                 if (style & WS_CHILD)
7173                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7174                 else if (style & WS_POPUP)
7175                     lParam = WND_POPUP_ID;
7176                 else
7177                     lParam = WND_PARENT_ID;
7178             }
7179             break;
7180
7181         /* test_accelerators() depends on this */
7182         case WM_NCHITTEST:
7183             return HTCLIENT;
7184
7185         /* ignore */
7186         case WM_MOUSEMOVE:
7187         case WM_MOUSEACTIVATE:
7188         case WM_NCMOUSEMOVE:
7189         case WM_SETCURSOR:
7190         case WM_IME_SELECT:
7191             return 0;
7192     }
7193
7194     msg.hwnd = hwnd;
7195     msg.message = message;
7196     msg.flags = sent|wparam|lparam;
7197     if (defwndproc_counter) msg.flags |= defwinproc;
7198     if (beginpaint_counter) msg.flags |= beginpaint;
7199     msg.wParam = wParam;
7200     msg.lParam = lParam;
7201     msg.descr = "MsgCheckProc";
7202     add_message(&msg);
7203
7204     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7205     {
7206         HWND parent = GetParent(hwnd);
7207         RECT rc;
7208         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7209
7210         GetClientRect(parent, &rc);
7211         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7212         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7213               minmax->ptReserved.x, minmax->ptReserved.y,
7214               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7215               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7216               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7217               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7218
7219         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7220            minmax->ptMaxSize.x, rc.right);
7221         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7222            minmax->ptMaxSize.y, rc.bottom);
7223     }
7224
7225     if (message == WM_PAINT)
7226     {
7227         PAINTSTRUCT ps;
7228         beginpaint_counter++;
7229         BeginPaint( hwnd, &ps );
7230         beginpaint_counter--;
7231         EndPaint( hwnd, &ps );
7232         return 0;
7233     }
7234
7235     defwndproc_counter++;
7236     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7237                   : DefWindowProcA(hwnd, message, wParam, lParam);
7238     defwndproc_counter--;
7239
7240     return ret;
7241 }
7242
7243 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7244 {
7245     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7246 }
7247
7248 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7249 {
7250     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7251 }
7252
7253 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7254 {
7255     static LONG defwndproc_counter = 0;
7256     LRESULT ret;
7257     struct recvd_message msg;
7258
7259     if (ignore_message( message )) return 0;
7260
7261     switch (message)
7262     {
7263     case WM_QUERYENDSESSION:
7264     case WM_ENDSESSION:
7265         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7266         break;
7267     }
7268
7269     msg.hwnd = hwnd;
7270     msg.message = message;
7271     msg.flags = sent|wparam|lparam;
7272     if (defwndproc_counter) msg.flags |= defwinproc;
7273     msg.wParam = wParam;
7274     msg.lParam = lParam;
7275     msg.descr = "popup";
7276     add_message(&msg);
7277
7278     if (message == WM_CREATE)
7279     {
7280         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7281         SetWindowLongA(hwnd, GWL_STYLE, style);
7282     }
7283
7284     defwndproc_counter++;
7285     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7286     defwndproc_counter--;
7287
7288     return ret;
7289 }
7290
7291 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7292 {
7293     static LONG defwndproc_counter = 0;
7294     static LONG beginpaint_counter = 0;
7295     LRESULT ret;
7296     struct recvd_message msg;
7297
7298     if (ignore_message( message )) return 0;
7299
7300     if (log_all_parent_messages ||
7301         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7302         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7303         message == WM_ENABLE || message == WM_ENTERIDLE ||
7304         message == WM_DRAWITEM || message == WM_COMMAND ||
7305         message == WM_IME_SETCONTEXT)
7306     {
7307         switch (message)
7308         {
7309             /* ignore */
7310             case WM_NCHITTEST:
7311                 return HTCLIENT;
7312             case WM_SETCURSOR:
7313             case WM_MOUSEMOVE:
7314             case WM_NCMOUSEMOVE:
7315                 return 0;
7316
7317             case WM_ERASEBKGND:
7318             {
7319                 RECT rc;
7320                 INT ret = GetClipBox((HDC)wParam, &rc);
7321
7322                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7323                        ret, rc.left, rc.top, rc.right, rc.bottom);
7324                 break;
7325             }
7326         }
7327
7328         msg.hwnd = hwnd;
7329         msg.message = message;
7330         msg.flags = sent|parent|wparam|lparam;
7331         if (defwndproc_counter) msg.flags |= defwinproc;
7332         if (beginpaint_counter) msg.flags |= beginpaint;
7333         msg.wParam = wParam;
7334         msg.lParam = lParam;
7335         msg.descr = "parent";
7336         add_message(&msg);
7337     }
7338
7339     if (message == WM_PAINT)
7340     {
7341         PAINTSTRUCT ps;
7342         beginpaint_counter++;
7343         BeginPaint( hwnd, &ps );
7344         beginpaint_counter--;
7345         EndPaint( hwnd, &ps );
7346         return 0;
7347     }
7348
7349     defwndproc_counter++;
7350     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7351     defwndproc_counter--;
7352
7353     return ret;
7354 }
7355
7356 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7357 {
7358     static LONG defwndproc_counter = 0;
7359     LRESULT ret;
7360     struct recvd_message msg;
7361
7362     if (ignore_message( message )) return 0;
7363
7364     if (test_def_id)
7365     {
7366         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7367         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7368         if (after_end_dialog)
7369             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7370         else
7371             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7372     }
7373
7374     msg.hwnd = hwnd;
7375     msg.message = message;
7376     msg.flags = sent|wparam|lparam;
7377     if (defwndproc_counter) msg.flags |= defwinproc;
7378     msg.wParam = wParam;
7379     msg.lParam = lParam;
7380     msg.descr = "dialog";
7381     add_message(&msg);
7382
7383     defwndproc_counter++;
7384     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7385     defwndproc_counter--;
7386
7387     return ret;
7388 }
7389
7390 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7391 {
7392     static LONG defwndproc_counter = 0;
7393     LRESULT ret;
7394     struct recvd_message msg;
7395
7396     /* log only specific messages we are interested in */
7397     switch (message)
7398     {
7399 #if 0 /* probably log these as well */
7400     case WM_ACTIVATE:
7401     case WM_SETFOCUS:
7402     case WM_KILLFOCUS:
7403 #endif
7404     case WM_SHOWWINDOW:
7405     case WM_SIZE:
7406     case WM_MOVE:
7407     case WM_GETMINMAXINFO:
7408     case WM_WINDOWPOSCHANGING:
7409     case WM_WINDOWPOSCHANGED:
7410         break;
7411
7412     default: /* ignore */
7413         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7414         return DefWindowProcA(hwnd, message, wParam, lParam);
7415     }
7416
7417     msg.hwnd = hwnd;
7418     msg.message = message;
7419     msg.flags = sent|wparam|lparam;
7420     if (defwndproc_counter) msg.flags |= defwinproc;
7421     msg.wParam = wParam;
7422     msg.lParam = lParam;
7423     msg.descr = "show";
7424     add_message(&msg);
7425
7426     defwndproc_counter++;
7427     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7428     defwndproc_counter--;
7429
7430     return ret;
7431 }
7432
7433 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7434 {
7435     switch (msg)
7436     {
7437         case WM_CREATE: return 0;
7438         case WM_PAINT:
7439         {
7440             MSG msg2;
7441             static int i = 0;
7442
7443             if (i < 256)
7444             {
7445                 i++;
7446                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7447                 {
7448                     TranslateMessage(&msg2);
7449                     DispatchMessage(&msg2);
7450                 }
7451                 i--;
7452             }
7453             else ok(broken(1), "infinite loop\n");
7454             if ( i == 0)
7455                 paint_loop_done = 1;
7456             return DefWindowProcA(hWnd,msg,wParam,lParam);
7457         }
7458     }
7459     return DefWindowProcA(hWnd,msg,wParam,lParam);
7460 }
7461
7462 static BOOL RegisterWindowClasses(void)
7463 {
7464     WNDCLASSA cls;
7465     WNDCLASSW clsW;
7466
7467     cls.style = 0;
7468     cls.lpfnWndProc = MsgCheckProcA;
7469     cls.cbClsExtra = 0;
7470     cls.cbWndExtra = 0;
7471     cls.hInstance = GetModuleHandleA(0);
7472     cls.hIcon = 0;
7473     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7474     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7475     cls.lpszMenuName = NULL;
7476     cls.lpszClassName = "TestWindowClass";
7477     if(!RegisterClassA(&cls)) return FALSE;
7478
7479     cls.lpfnWndProc = ShowWindowProcA;
7480     cls.lpszClassName = "ShowWindowClass";
7481     if(!RegisterClassA(&cls)) return FALSE;
7482
7483     cls.lpfnWndProc = PopupMsgCheckProcA;
7484     cls.lpszClassName = "TestPopupClass";
7485     if(!RegisterClassA(&cls)) return FALSE;
7486
7487     cls.lpfnWndProc = ParentMsgCheckProcA;
7488     cls.lpszClassName = "TestParentClass";
7489     if(!RegisterClassA(&cls)) return FALSE;
7490
7491     cls.lpfnWndProc = DefWindowProcA;
7492     cls.lpszClassName = "SimpleWindowClass";
7493     if(!RegisterClassA(&cls)) return FALSE;
7494
7495     cls.lpfnWndProc = PaintLoopProcA;
7496     cls.lpszClassName = "PaintLoopWindowClass";
7497     if(!RegisterClassA(&cls)) return FALSE;
7498
7499     cls.style = CS_NOCLOSE;
7500     cls.lpszClassName = "NoCloseWindowClass";
7501     if(!RegisterClassA(&cls)) return FALSE;
7502
7503     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7504     cls.style = 0;
7505     cls.hInstance = GetModuleHandleA(0);
7506     cls.hbrBackground = 0;
7507     cls.lpfnWndProc = TestDlgProcA;
7508     cls.lpszClassName = "TestDialogClass";
7509     if(!RegisterClassA(&cls)) return FALSE;
7510
7511     clsW.style = 0;
7512     clsW.lpfnWndProc = MsgCheckProcW;
7513     clsW.cbClsExtra = 0;
7514     clsW.cbWndExtra = 0;
7515     clsW.hInstance = GetModuleHandleW(0);
7516     clsW.hIcon = 0;
7517     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7518     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7519     clsW.lpszMenuName = NULL;
7520     clsW.lpszClassName = testWindowClassW;
7521     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7522
7523     return TRUE;
7524 }
7525
7526 static BOOL is_our_logged_class(HWND hwnd)
7527 {
7528     char buf[256];
7529
7530     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7531     {
7532         if (!lstrcmpiA(buf, "TestWindowClass") ||
7533             !lstrcmpiA(buf, "ShowWindowClass") ||
7534             !lstrcmpiA(buf, "TestParentClass") ||
7535             !lstrcmpiA(buf, "TestPopupClass") ||
7536             !lstrcmpiA(buf, "SimpleWindowClass") ||
7537             !lstrcmpiA(buf, "TestDialogClass") ||
7538             !lstrcmpiA(buf, "MDI_frame_class") ||
7539             !lstrcmpiA(buf, "MDI_client_class") ||
7540             !lstrcmpiA(buf, "MDI_child_class") ||
7541             !lstrcmpiA(buf, "my_button_class") ||
7542             !lstrcmpiA(buf, "my_edit_class") ||
7543             !lstrcmpiA(buf, "static") ||
7544             !lstrcmpiA(buf, "ListBox") ||
7545             !lstrcmpiA(buf, "ComboBox") ||
7546             !lstrcmpiA(buf, "MyDialogClass") ||
7547             !lstrcmpiA(buf, "#32770") ||
7548             !lstrcmpiA(buf, "#32768"))
7549         return TRUE;
7550     }
7551     return FALSE;
7552 }
7553
7554 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7555
7556     HWND hwnd;
7557
7558     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7559
7560     if (nCode == HCBT_CLICKSKIPPED)
7561     {
7562         /* ignore this event, XP sends it a lot when switching focus between windows */
7563         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7564     }
7565
7566     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7567     {
7568         struct recvd_message msg;
7569
7570         msg.hwnd = 0;
7571         msg.message = nCode;
7572         msg.flags = hook|wparam|lparam;
7573         msg.wParam = wParam;
7574         msg.lParam = lParam;
7575         msg.descr = "CBT";
7576         add_message(&msg);
7577
7578         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7579     }
7580
7581     if (nCode == HCBT_DESTROYWND)
7582     {
7583         if (test_DestroyWindow_flag)
7584         {
7585             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7586             if (style & WS_CHILD)
7587                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7588             else if (style & WS_POPUP)
7589                 lParam = WND_POPUP_ID;
7590             else
7591                 lParam = WND_PARENT_ID;
7592         }
7593     }
7594
7595     /* Log also SetFocus(0) calls */
7596     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7597
7598     if (is_our_logged_class(hwnd))
7599     {
7600         struct recvd_message msg;
7601
7602         msg.hwnd = hwnd;
7603         msg.message = nCode;
7604         msg.flags = hook|wparam|lparam;
7605         msg.wParam = wParam;
7606         msg.lParam = lParam;
7607         msg.descr = "CBT";
7608         add_message(&msg);
7609     }
7610     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7611 }
7612
7613 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7614                                     DWORD event,
7615                                     HWND hwnd,
7616                                     LONG object_id,
7617                                     LONG child_id,
7618                                     DWORD thread_id,
7619                                     DWORD event_time)
7620 {
7621     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7622
7623     /* ignore mouse cursor events */
7624     if (object_id == OBJID_CURSOR) return;
7625
7626     if (!hwnd || is_our_logged_class(hwnd))
7627     {
7628         struct recvd_message msg;
7629
7630         msg.hwnd = hwnd;
7631         msg.message = event;
7632         msg.flags = winevent_hook|wparam|lparam;
7633         msg.wParam = object_id;
7634         msg.lParam = child_id;
7635         msg.descr = "WEH";
7636         add_message(&msg);
7637     }
7638 }
7639
7640 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7641 static const WCHAR wszAnsi[] = {'U',0};
7642
7643 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7644 {
7645     switch (uMsg)
7646     {
7647     case CB_FINDSTRINGEXACT:
7648         trace("String: %p\n", (LPCWSTR)lParam);
7649         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7650             return 1;
7651         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7652             return 0;
7653         return -1;
7654     }
7655     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7656 }
7657
7658 static const struct message WmGetTextLengthAfromW[] = {
7659     { WM_GETTEXTLENGTH, sent },
7660     { WM_GETTEXT, sent|optional },
7661     { 0 }
7662 };
7663
7664 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7665
7666 /* dummy window proc for WM_GETTEXTLENGTH test */
7667 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7668 {
7669     switch(msg)
7670     {
7671     case WM_GETTEXTLENGTH:
7672         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7673     case WM_GETTEXT:
7674         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7675         return lstrlenW( (LPWSTR)lp );
7676     default:
7677         return DefWindowProcW( hwnd, msg, wp, lp );
7678     }
7679 }
7680
7681 static void test_message_conversion(void)
7682 {
7683     static const WCHAR wszMsgConversionClass[] =
7684         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7685     WNDCLASSW cls;
7686     LRESULT lRes;
7687     HWND hwnd;
7688     WNDPROC wndproc, newproc;
7689     BOOL ret;
7690
7691     cls.style = 0;
7692     cls.lpfnWndProc = MsgConversionProcW;
7693     cls.cbClsExtra = 0;
7694     cls.cbWndExtra = 0;
7695     cls.hInstance = GetModuleHandleW(NULL);
7696     cls.hIcon = NULL;
7697     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7698     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7699     cls.lpszMenuName = NULL;
7700     cls.lpszClassName = wszMsgConversionClass;
7701     /* this call will fail on Win9x, but that doesn't matter as this test is
7702      * meaningless on those platforms */
7703     if(!RegisterClassW(&cls)) return;
7704
7705     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7706                            100, 100, 200, 200, 0, 0, 0, NULL);
7707     ok(hwnd != NULL, "Window creation failed\n");
7708
7709     /* {W, A} -> A */
7710
7711     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7712     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7713     ok(lRes == 0, "String should have been converted\n");
7714     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7715     ok(lRes == 1, "String shouldn't have been converted\n");
7716
7717     /* {W, A} -> W */
7718
7719     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7720     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7721     ok(lRes == 1, "String shouldn't have been converted\n");
7722     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7723     ok(lRes == 1, "String shouldn't have been converted\n");
7724
7725     /* Synchronous messages */
7726
7727     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7728     ok(lRes == 0, "String should have been converted\n");
7729     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7730     ok(lRes == 1, "String shouldn't have been converted\n");
7731
7732     /* Asynchronous messages */
7733
7734     SetLastError(0);
7735     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7736     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7737         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7738     SetLastError(0);
7739     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7740     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7741         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7742     SetLastError(0);
7743     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7744     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7745         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7746     SetLastError(0);
7747     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7748     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7749         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7750     SetLastError(0);
7751     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7752     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7753         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7754     SetLastError(0);
7755     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7756     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7757         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7758     SetLastError(0);
7759     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7760     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7761         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7762     SetLastError(0);
7763     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7764     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7765         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7766
7767     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7768
7769     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7770                           WS_OVERLAPPEDWINDOW,
7771                           100, 100, 200, 200, 0, 0, 0, NULL);
7772     assert(hwnd);
7773     flush_sequence();
7774     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7775     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7776     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7777         "got bad length %ld\n", lRes );
7778
7779     flush_sequence();
7780     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7781                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7782     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7783     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7784         "got bad length %ld\n", lRes );
7785
7786     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7787     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7788     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7789     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7790                                      NULL, 0, NULL, NULL ) ||
7791         broken(lRes == lstrlenW(dummy_window_text) + 37),
7792         "got bad length %ld\n", lRes );
7793
7794     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7795     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7796     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7797                                      NULL, 0, NULL, NULL ) ||
7798         broken(lRes == lstrlenW(dummy_window_text) + 37),
7799         "got bad length %ld\n", lRes );
7800
7801     ret = DestroyWindow(hwnd);
7802     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7803 }
7804
7805 struct timer_info
7806 {
7807     HWND hWnd;
7808     HANDLE handles[2];
7809     DWORD id;
7810 };
7811
7812 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7813 {
7814 }
7815
7816 #define TIMER_ID  0x19
7817
7818 static DWORD WINAPI timer_thread_proc(LPVOID x)
7819 {
7820     struct timer_info *info = x;
7821     DWORD r;
7822
7823     r = KillTimer(info->hWnd, 0x19);
7824     ok(r,"KillTimer failed in thread\n");
7825     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7826     ok(r,"SetTimer failed in thread\n");
7827     ok(r==TIMER_ID,"SetTimer id different\n");
7828     r = SetEvent(info->handles[0]);
7829     ok(r,"SetEvent failed in thread\n");
7830     return 0;
7831 }
7832
7833 static void test_timers(void)
7834 {
7835     struct timer_info info;
7836     DWORD id;
7837
7838     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7839        WS_OVERLAPPEDWINDOW ,
7840        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7841        NULL, NULL, 0);
7842
7843     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7844     ok(info.id, "SetTimer failed\n");
7845     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7846     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7847     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7848
7849     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7850
7851     WaitForSingleObject(info.handles[1], INFINITE);
7852
7853     CloseHandle(info.handles[0]);
7854     CloseHandle(info.handles[1]);
7855
7856     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7857
7858     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7859 }
7860
7861 static int count = 0;
7862 static VOID CALLBACK callback_count(
7863     HWND hwnd,
7864     UINT uMsg,
7865     UINT_PTR idEvent,
7866     DWORD dwTime
7867 )
7868 {
7869     count++;
7870 }
7871
7872 static void test_timers_no_wnd(void)
7873 {
7874     UINT_PTR id, id2;
7875     MSG msg;
7876
7877     count = 0;
7878     id = SetTimer(NULL, 0, 100, callback_count);
7879     ok(id != 0, "did not get id from SetTimer.\n");
7880     id2 = SetTimer(NULL, id, 200, callback_count);
7881     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7882     Sleep(150);
7883     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7884     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7885     Sleep(150);
7886     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7887     ok(count == 1, "did not get one count as expected (%i).\n", count);
7888     KillTimer(NULL, id);
7889     Sleep(250);
7890     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7891     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7892 }
7893
7894 /* Various win events with arbitrary parameters */
7895 static const struct message WmWinEventsSeq[] = {
7896     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7897     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7898     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7899     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7900     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7901     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7902     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7903     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7904     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7905     /* our win event hook ignores OBJID_CURSOR events */
7906     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7907     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7908     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7909     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7910     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7911     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7912     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7913     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7914     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7915     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7916     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7917     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7918     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7919     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7920     { 0 }
7921 };
7922 static const struct message WmWinEventCaretSeq[] = {
7923     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7924     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7925     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7926     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7927     { 0 }
7928 };
7929 static const struct message WmWinEventCaretSeq_2[] = {
7930     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7931     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7932     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7933     { 0 }
7934 };
7935 static const struct message WmWinEventAlertSeq[] = {
7936     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7937     { 0 }
7938 };
7939 static const struct message WmWinEventAlertSeq_2[] = {
7940     /* create window in the thread proc */
7941     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7942     /* our test event */
7943     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7944     { 0 }
7945 };
7946 static const struct message WmGlobalHookSeq_1[] = {
7947     /* create window in the thread proc */
7948     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7949     /* our test events */
7950     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7951     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7952     { 0 }
7953 };
7954 static const struct message WmGlobalHookSeq_2[] = {
7955     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7956     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7957     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7958     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7959     { 0 }
7960 };
7961
7962 static const struct message WmMouseLLHookSeq[] = {
7963     { WM_MOUSEMOVE, hook },
7964     { WM_LBUTTONUP, hook },
7965     { WM_MOUSEMOVE, hook },
7966     { 0 }
7967 };
7968
7969 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7970                                          DWORD event,
7971                                          HWND hwnd,
7972                                          LONG object_id,
7973                                          LONG child_id,
7974                                          DWORD thread_id,
7975                                          DWORD event_time)
7976 {
7977     char buf[256];
7978
7979     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7980     {
7981         if (!lstrcmpiA(buf, "TestWindowClass") ||
7982             !lstrcmpiA(buf, "static"))
7983         {
7984             struct recvd_message msg;
7985
7986             msg.hwnd = hwnd;
7987             msg.message = event;
7988             msg.flags = winevent_hook|wparam|lparam;
7989             msg.wParam = object_id;
7990             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7991             msg.descr = "WEH_2";
7992             add_message(&msg);
7993         }
7994     }
7995 }
7996
7997 static HHOOK hCBT_global_hook;
7998 static DWORD cbt_global_hook_thread_id;
7999
8000 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
8001
8002     HWND hwnd;
8003     char buf[256];
8004
8005     if (nCode == HCBT_SYSCOMMAND)
8006     {
8007         struct recvd_message msg;
8008
8009         msg.hwnd = 0;
8010         msg.message = nCode;
8011         msg.flags = hook|wparam|lparam;
8012         msg.wParam = wParam;
8013         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8014         msg.descr = "CBT_2";
8015         add_message(&msg);
8016
8017         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8018     }
8019     /* WH_MOUSE_LL hook */
8020     if (nCode == HC_ACTION)
8021     {
8022         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8023
8024         /* we can't test for real mouse events */
8025         if (mhll->flags & LLMHF_INJECTED)
8026         {
8027             struct recvd_message msg;
8028
8029             memset (&msg, 0, sizeof (msg));
8030             msg.message = wParam;
8031             msg.flags = hook;
8032             msg.descr = "CBT_2";
8033             add_message(&msg);
8034         }
8035         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8036     }
8037
8038     /* Log also SetFocus(0) calls */
8039     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8040
8041     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8042     {
8043         if (!lstrcmpiA(buf, "TestWindowClass") ||
8044             !lstrcmpiA(buf, "static"))
8045         {
8046             struct recvd_message msg;
8047
8048             msg.hwnd = hwnd;
8049             msg.message = nCode;
8050             msg.flags = hook|wparam|lparam;
8051             msg.wParam = wParam;
8052             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8053             msg.descr = "CBT_2";
8054             add_message(&msg);
8055         }
8056     }
8057     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8058 }
8059
8060 static DWORD WINAPI win_event_global_thread_proc(void *param)
8061 {
8062     HWND hwnd;
8063     MSG msg;
8064     HANDLE hevent = *(HANDLE *)param;
8065
8066     assert(pNotifyWinEvent);
8067
8068     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8069     assert(hwnd);
8070     trace("created thread window %p\n", hwnd);
8071
8072     *(HWND *)param = hwnd;
8073
8074     flush_sequence();
8075     /* this event should be received only by our new hook proc,
8076      * an old one does not expect an event from another thread.
8077      */
8078     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8079     SetEvent(hevent);
8080
8081     while (GetMessage(&msg, 0, 0, 0))
8082     {
8083         TranslateMessage(&msg);
8084         DispatchMessage(&msg);
8085     }
8086     return 0;
8087 }
8088
8089 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8090 {
8091     HWND hwnd;
8092     MSG msg;
8093     HANDLE hevent = *(HANDLE *)param;
8094
8095     flush_sequence();
8096     /* these events should be received only by our new hook proc,
8097      * an old one does not expect an event from another thread.
8098      */
8099
8100     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8101     assert(hwnd);
8102     trace("created thread window %p\n", hwnd);
8103
8104     *(HWND *)param = hwnd;
8105
8106     /* Windows doesn't like when a thread plays games with the focus,
8107        that leads to all kinds of misbehaviours and failures to activate
8108        a window. So, better keep next lines commented out.
8109     SetFocus(0);
8110     SetFocus(hwnd);*/
8111
8112     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8113     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8114
8115     SetEvent(hevent);
8116
8117     while (GetMessage(&msg, 0, 0, 0))
8118     {
8119         TranslateMessage(&msg);
8120         DispatchMessage(&msg);
8121     }
8122     return 0;
8123 }
8124
8125 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8126 {
8127     HWND hwnd;
8128     MSG msg;
8129     HANDLE hevent = *(HANDLE *)param;
8130
8131     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8132     assert(hwnd);
8133     trace("created thread window %p\n", hwnd);
8134
8135     *(HWND *)param = hwnd;
8136
8137     flush_sequence();
8138
8139     /* Windows doesn't like when a thread plays games with the focus,
8140      * that leads to all kinds of misbehaviours and failures to activate
8141      * a window. So, better don't generate a mouse click message below.
8142      */
8143     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8144     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8145     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8146
8147     SetEvent(hevent);
8148     while (GetMessage(&msg, 0, 0, 0))
8149     {
8150         TranslateMessage(&msg);
8151         DispatchMessage(&msg);
8152     }
8153     return 0;
8154 }
8155
8156 static void test_winevents(void)
8157 {
8158     BOOL ret;
8159     MSG msg;
8160     HWND hwnd, hwnd2;
8161     UINT i;
8162     HANDLE hthread, hevent;
8163     DWORD tid;
8164     HWINEVENTHOOK hhook;
8165     const struct message *events = WmWinEventsSeq;
8166
8167     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8168                            WS_OVERLAPPEDWINDOW,
8169                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8170                            NULL, NULL, 0);
8171     assert(hwnd);
8172
8173     /****** start of global hook test *************/
8174     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8175     if (!hCBT_global_hook)
8176     {
8177         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8178         skip( "cannot set global hook\n" );
8179         return;
8180     }
8181
8182     hevent = CreateEventA(NULL, 0, 0, NULL);
8183     assert(hevent);
8184     hwnd2 = hevent;
8185
8186     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8187     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8188
8189     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8190
8191     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8192
8193     flush_sequence();
8194     /* this one should be received only by old hook proc */
8195     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8196     /* this one should be received only by old hook proc */
8197     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8198
8199     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8200
8201     ret = UnhookWindowsHookEx(hCBT_global_hook);
8202     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8203
8204     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8205     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8206     CloseHandle(hthread);
8207     CloseHandle(hevent);
8208     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8209     /****** end of global hook test *************/
8210
8211     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8212     {
8213         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8214         return;
8215     }
8216
8217     flush_sequence();
8218
8219     if (0)
8220     {
8221     /* this test doesn't pass under Win9x */
8222     /* win2k ignores events with hwnd == 0 */
8223     SetLastError(0xdeadbeef);
8224     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8225     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8226        GetLastError() == 0xdeadbeef, /* Win9x */
8227        "unexpected error %d\n", GetLastError());
8228     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8229     }
8230
8231     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8232         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8233
8234     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8235
8236     /****** start of event filtering test *************/
8237     hhook = pSetWinEventHook(
8238         EVENT_OBJECT_SHOW, /* 0x8002 */
8239         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8240         GetModuleHandleA(0), win_event_global_hook_proc,
8241         GetCurrentProcessId(), 0,
8242         WINEVENT_INCONTEXT);
8243     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8244
8245     hevent = CreateEventA(NULL, 0, 0, NULL);
8246     assert(hevent);
8247     hwnd2 = hevent;
8248
8249     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8250     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8251
8252     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8253
8254     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8255
8256     flush_sequence();
8257     /* this one should be received only by old hook proc */
8258     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8259     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8260     /* this one should be received only by old hook proc */
8261     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8262
8263     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8264
8265     ret = pUnhookWinEvent(hhook);
8266     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8267
8268     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8269     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8270     CloseHandle(hthread);
8271     CloseHandle(hevent);
8272     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8273     /****** end of event filtering test *************/
8274
8275     /****** start of out of context event test *************/
8276     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8277         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8278         WINEVENT_OUTOFCONTEXT);
8279     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8280
8281     hevent = CreateEventA(NULL, 0, 0, NULL);
8282     assert(hevent);
8283     hwnd2 = hevent;
8284
8285     flush_sequence();
8286
8287     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8288     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8289
8290     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8291
8292     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8293     /* process pending winevent messages */
8294     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8295     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8296
8297     flush_sequence();
8298     /* this one should be received only by old hook proc */
8299     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8300     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8301     /* this one should be received only by old hook proc */
8302     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8303
8304     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8305     /* process pending winevent messages */
8306     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8307     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8308
8309     ret = pUnhookWinEvent(hhook);
8310     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8311
8312     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8313     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8314     CloseHandle(hthread);
8315     CloseHandle(hevent);
8316     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8317     /****** end of out of context event test *************/
8318
8319     /****** start of MOUSE_LL hook test *************/
8320     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8321     /* WH_MOUSE_LL is not supported on Win9x platforms */
8322     if (!hCBT_global_hook)
8323     {
8324         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8325         goto skip_mouse_ll_hook_test;
8326     }
8327
8328     hevent = CreateEventA(NULL, 0, 0, NULL);
8329     assert(hevent);
8330     hwnd2 = hevent;
8331
8332     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8333     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8334
8335     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8336         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8337
8338     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8339     flush_sequence();
8340
8341     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8342     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8343     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8344
8345     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8346
8347     ret = UnhookWindowsHookEx(hCBT_global_hook);
8348     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8349
8350     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8351     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8352     CloseHandle(hthread);
8353     CloseHandle(hevent);
8354     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8355     /****** end of MOUSE_LL hook test *************/
8356 skip_mouse_ll_hook_test:
8357
8358     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8359 }
8360
8361 static void test_set_hook(void)
8362 {
8363     BOOL ret;
8364     HHOOK hhook;
8365     HWINEVENTHOOK hwinevent_hook;
8366
8367     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8368     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8369     UnhookWindowsHookEx(hhook);
8370
8371     if (0)
8372     {
8373     /* this test doesn't pass under Win9x: BUG! */
8374     SetLastError(0xdeadbeef);
8375     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8376     ok(!hhook, "global hook requires hModule != 0\n");
8377     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8378     }
8379
8380     SetLastError(0xdeadbeef);
8381     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8382     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8383     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8384        GetLastError() == 0xdeadbeef, /* Win9x */
8385        "unexpected error %d\n", GetLastError());
8386
8387     SetLastError(0xdeadbeef);
8388     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8389     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8390        GetLastError() == 0xdeadbeef, /* Win9x */
8391        "unexpected error %d\n", GetLastError());
8392
8393     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8394
8395     /* even process local incontext hooks require hmodule */
8396     SetLastError(0xdeadbeef);
8397     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8398         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8399     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8400     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8401        GetLastError() == 0xdeadbeef, /* Win9x */
8402        "unexpected error %d\n", GetLastError());
8403
8404     /* even thread local incontext hooks require hmodule */
8405     SetLastError(0xdeadbeef);
8406     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8407         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8408     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8409     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8410        GetLastError() == 0xdeadbeef, /* Win9x */
8411        "unexpected error %d\n", GetLastError());
8412
8413     if (0)
8414     {
8415     /* these 3 tests don't pass under Win9x */
8416     SetLastError(0xdeadbeef);
8417     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8418         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8419     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8420     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8421
8422     SetLastError(0xdeadbeef);
8423     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8424         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8425     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8426     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8427
8428     SetLastError(0xdeadbeef);
8429     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8430         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8431     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8432     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8433     }
8434
8435     SetLastError(0xdeadbeef);
8436     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8437         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8438     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8439     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8440     ret = pUnhookWinEvent(hwinevent_hook);
8441     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8442
8443 todo_wine {
8444     /* This call succeeds under win2k SP4, but fails under Wine.
8445        Does win2k test/use passed process id? */
8446     SetLastError(0xdeadbeef);
8447     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8448         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8449     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8450     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8451     ret = pUnhookWinEvent(hwinevent_hook);
8452     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8453 }
8454
8455     SetLastError(0xdeadbeef);
8456     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8457     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8458         GetLastError() == 0xdeadbeef, /* Win9x */
8459         "unexpected error %d\n", GetLastError());
8460 }
8461
8462 static const struct message ScrollWindowPaint1[] = {
8463     { WM_PAINT, sent },
8464     { WM_ERASEBKGND, sent|beginpaint },
8465     { WM_GETTEXTLENGTH, sent|optional },
8466     { WM_PAINT, sent|optional },
8467     { WM_NCPAINT, sent|beginpaint|optional },
8468     { WM_GETTEXT, sent|beginpaint|optional },
8469     { WM_GETTEXT, sent|beginpaint|optional },
8470     { WM_GETTEXT, sent|beginpaint|optional },
8471     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8472     { WM_ERASEBKGND, sent|beginpaint|optional },
8473     { 0 }
8474 };
8475
8476 static const struct message ScrollWindowPaint2[] = {
8477     { WM_PAINT, sent },
8478     { 0 }
8479 };
8480
8481 static void test_scrollwindowex(void)
8482 {
8483     HWND hwnd, hchild;
8484     RECT rect={0,0,130,130};
8485
8486     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8487             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8488             100, 100, 200, 200, 0, 0, 0, NULL);
8489     ok (hwnd != 0, "Failed to create overlapped window\n");
8490     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8491             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8492             10, 10, 150, 150, hwnd, 0, 0, NULL);
8493     ok (hchild != 0, "Failed to create child\n");
8494     UpdateWindow(hwnd);
8495     flush_events();
8496     flush_sequence();
8497
8498     /* scroll without the child window */
8499     trace("start scroll\n");
8500     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8501             SW_ERASE|SW_INVALIDATE);
8502     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8503     trace("end scroll\n");
8504     flush_sequence();
8505     flush_events();
8506     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8507     flush_events();
8508     flush_sequence();
8509
8510     /* Now without the SW_ERASE flag */
8511     trace("start scroll\n");
8512     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8513     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8514     trace("end scroll\n");
8515     flush_sequence();
8516     flush_events();
8517     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8518     flush_events();
8519     flush_sequence();
8520
8521     /* now scroll the child window as well */
8522     trace("start scroll\n");
8523     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8524             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8525     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8526     /* windows sometimes a WM_MOVE */
8527     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8528     trace("end scroll\n");
8529     flush_sequence();
8530     flush_events();
8531     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8532     flush_events();
8533     flush_sequence();
8534
8535     /* now scroll with ScrollWindow() */
8536     trace("start scroll with ScrollWindow\n");
8537     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8538     trace("end scroll\n");
8539     flush_sequence();
8540     flush_events();
8541     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8542
8543     ok(DestroyWindow(hchild), "failed to destroy window\n");
8544     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8545     flush_sequence();
8546 }
8547
8548 static const struct message destroy_window_with_children[] = {
8549     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8550     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8551     { 0x0090, sent|optional },
8552     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8553     { 0x0090, sent|optional },
8554     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8555     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8556     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8557     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8558     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8559     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8560     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8561     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8562     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8563     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8564     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8565     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8566     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8567     { 0 }
8568 };
8569
8570 static void test_DestroyWindow(void)
8571 {
8572     BOOL ret;
8573     HWND parent, child1, child2, child3, child4, test;
8574     UINT_PTR child_id = WND_CHILD_ID + 1;
8575
8576     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8577                              100, 100, 200, 200, 0, 0, 0, NULL);
8578     assert(parent != 0);
8579     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8580                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8581     assert(child1 != 0);
8582     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8583                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8584     assert(child2 != 0);
8585     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8586                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8587     assert(child3 != 0);
8588     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8589                              0, 0, 50, 50, parent, 0, 0, NULL);
8590     assert(child4 != 0);
8591
8592     /* test owner/parent of child2 */
8593     test = GetParent(child2);
8594     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8595     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8596     if(pGetAncestor) {
8597         test = pGetAncestor(child2, GA_PARENT);
8598         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8599     }
8600     test = GetWindow(child2, GW_OWNER);
8601     ok(!test, "wrong owner %p\n", test);
8602
8603     test = SetParent(child2, parent);
8604     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8605
8606     /* test owner/parent of the parent */
8607     test = GetParent(parent);
8608     ok(!test, "wrong parent %p\n", test);
8609     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8610     if(pGetAncestor) {
8611         test = pGetAncestor(parent, GA_PARENT);
8612         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8613     }
8614     test = GetWindow(parent, GW_OWNER);
8615     ok(!test, "wrong owner %p\n", test);
8616
8617     /* test owner/parent of child1 */
8618     test = GetParent(child1);
8619     ok(test == parent, "wrong parent %p\n", test);
8620     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8621     if(pGetAncestor) {
8622         test = pGetAncestor(child1, GA_PARENT);
8623         ok(test == parent, "wrong parent %p\n", test);
8624     }
8625     test = GetWindow(child1, GW_OWNER);
8626     ok(!test, "wrong owner %p\n", test);
8627
8628     /* test owner/parent of child2 */
8629     test = GetParent(child2);
8630     ok(test == parent, "wrong parent %p\n", test);
8631     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8632     if(pGetAncestor) {
8633         test = pGetAncestor(child2, GA_PARENT);
8634         ok(test == parent, "wrong parent %p\n", test);
8635     }
8636     test = GetWindow(child2, GW_OWNER);
8637     ok(!test, "wrong owner %p\n", test);
8638
8639     /* test owner/parent of child3 */
8640     test = GetParent(child3);
8641     ok(test == child1, "wrong parent %p\n", test);
8642     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8643     if(pGetAncestor) {
8644         test = pGetAncestor(child3, GA_PARENT);
8645         ok(test == child1, "wrong parent %p\n", test);
8646     }
8647     test = GetWindow(child3, GW_OWNER);
8648     ok(!test, "wrong owner %p\n", test);
8649
8650     /* test owner/parent of child4 */
8651     test = GetParent(child4);
8652     ok(test == parent, "wrong parent %p\n", test);
8653     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8654     if(pGetAncestor) {
8655         test = pGetAncestor(child4, GA_PARENT);
8656         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8657     }
8658     test = GetWindow(child4, GW_OWNER);
8659     ok(test == parent, "wrong owner %p\n", test);
8660
8661     flush_sequence();
8662
8663     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8664            parent, child1, child2, child3, child4);
8665
8666     SetCapture(child4);
8667     test = GetCapture();
8668     ok(test == child4, "wrong capture window %p\n", test);
8669
8670     test_DestroyWindow_flag = TRUE;
8671     ret = DestroyWindow(parent);
8672     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8673     test_DestroyWindow_flag = FALSE;
8674     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8675
8676     ok(!IsWindow(parent), "parent still exists\n");
8677     ok(!IsWindow(child1), "child1 still exists\n");
8678     ok(!IsWindow(child2), "child2 still exists\n");
8679     ok(!IsWindow(child3), "child3 still exists\n");
8680     ok(!IsWindow(child4), "child4 still exists\n");
8681
8682     test = GetCapture();
8683     ok(!test, "wrong capture window %p\n", test);
8684 }
8685
8686
8687 static const struct message WmDispatchPaint[] = {
8688     { WM_NCPAINT, sent },
8689     { WM_GETTEXT, sent|defwinproc|optional },
8690     { WM_GETTEXT, sent|defwinproc|optional },
8691     { WM_ERASEBKGND, sent },
8692     { 0 }
8693 };
8694
8695 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8696 {
8697     if (message == WM_PAINT) return 0;
8698     return MsgCheckProcA( hwnd, message, wParam, lParam );
8699 }
8700
8701 static void test_DispatchMessage(void)
8702 {
8703     RECT rect;
8704     MSG msg;
8705     int count;
8706     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8707                                100, 100, 200, 200, 0, 0, 0, NULL);
8708     ShowWindow( hwnd, SW_SHOW );
8709     UpdateWindow( hwnd );
8710     flush_events();
8711     flush_sequence();
8712     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8713
8714     SetRect( &rect, -5, -5, 5, 5 );
8715     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8716     count = 0;
8717     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8718     {
8719         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8720         else
8721         {
8722             flush_sequence();
8723             DispatchMessage( &msg );
8724             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8725             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8726             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8727             if (++count > 10) break;
8728         }
8729     }
8730     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8731
8732     trace("now without DispatchMessage\n");
8733     flush_sequence();
8734     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8735     count = 0;
8736     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8737     {
8738         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8739         else
8740         {
8741             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8742             flush_sequence();
8743             /* this will send WM_NCCPAINT just like DispatchMessage does */
8744             GetUpdateRgn( hwnd, hrgn, TRUE );
8745             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8746             DeleteObject( hrgn );
8747             GetClientRect( hwnd, &rect );
8748             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8749             ok( !count, "Got multiple WM_PAINTs\n" );
8750             if (++count > 10) break;
8751         }
8752     }
8753     DestroyWindow(hwnd);
8754 }
8755
8756
8757 static const struct message WmUser[] = {
8758     { WM_USER, sent },
8759     { 0 }
8760 };
8761
8762 struct sendmsg_info
8763 {
8764     HWND  hwnd;
8765     DWORD timeout;
8766     DWORD ret;
8767 };
8768
8769 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8770 {
8771     struct sendmsg_info *info = arg;
8772     SetLastError( 0xdeadbeef );
8773     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8774     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8775                         broken(GetLastError() == 0),  /* win9x */
8776                         "unexpected error %d\n", GetLastError());
8777     return 0;
8778 }
8779
8780 static void wait_for_thread( HANDLE thread )
8781 {
8782     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8783     {
8784         MSG msg;
8785         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8786     }
8787 }
8788
8789 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8790 {
8791     if (message == WM_USER) Sleep(200);
8792     return MsgCheckProcA( hwnd, message, wParam, lParam );
8793 }
8794
8795 static void test_SendMessageTimeout(void)
8796 {
8797     HANDLE thread;
8798     struct sendmsg_info info;
8799     DWORD tid;
8800     BOOL is_win9x;
8801
8802     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8803                                100, 100, 200, 200, 0, 0, 0, NULL);
8804     flush_events();
8805     flush_sequence();
8806
8807     info.timeout = 1000;
8808     info.ret = 0xdeadbeef;
8809     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8810     wait_for_thread( thread );
8811     CloseHandle( thread );
8812     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8813     ok_sequence( WmUser, "WmUser", FALSE );
8814
8815     info.timeout = 1;
8816     info.ret = 0xdeadbeef;
8817     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8818     Sleep(100);  /* SendMessageTimeout should time out here */
8819     wait_for_thread( thread );
8820     CloseHandle( thread );
8821     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8822     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8823
8824     /* 0 means infinite timeout (but not on win9x) */
8825     info.timeout = 0;
8826     info.ret = 0xdeadbeef;
8827     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8828     Sleep(100);
8829     wait_for_thread( thread );
8830     CloseHandle( thread );
8831     is_win9x = !info.ret;
8832     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8833     else ok_sequence( WmUser, "WmUser", FALSE );
8834
8835     /* timeout is treated as signed despite the prototype (but not on win9x) */
8836     info.timeout = 0x7fffffff;
8837     info.ret = 0xdeadbeef;
8838     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8839     Sleep(100);
8840     wait_for_thread( thread );
8841     CloseHandle( thread );
8842     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8843     ok_sequence( WmUser, "WmUser", FALSE );
8844
8845     info.timeout = 0x80000000;
8846     info.ret = 0xdeadbeef;
8847     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8848     Sleep(100);
8849     wait_for_thread( thread );
8850     CloseHandle( thread );
8851     if (is_win9x)
8852     {
8853         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8854         ok_sequence( WmUser, "WmUser", FALSE );
8855     }
8856     else
8857     {
8858         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8859         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8860     }
8861
8862     /* now check for timeout during message processing */
8863     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8864     info.timeout = 100;
8865     info.ret = 0xdeadbeef;
8866     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8867     wait_for_thread( thread );
8868     CloseHandle( thread );
8869     /* we should time out but still get the message */
8870     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8871     ok_sequence( WmUser, "WmUser", FALSE );
8872
8873     DestroyWindow( info.hwnd );
8874 }
8875
8876
8877 /****************** edit message test *************************/
8878 #define ID_EDIT 0x1234
8879 static const struct message sl_edit_setfocus[] =
8880 {
8881     { HCBT_SETFOCUS, hook },
8882     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8883     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8884     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8885     { WM_SETFOCUS, sent|wparam, 0 },
8886     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8887     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8888     { WM_CTLCOLOREDIT, sent|parent },
8889     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8890     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8891     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8892     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8893     { 0 }
8894 };
8895 static const struct message ml_edit_setfocus[] =
8896 {
8897     { HCBT_SETFOCUS, hook },
8898     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8899     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8900     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8901     { WM_SETFOCUS, sent|wparam, 0 },
8902     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8903     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8904     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8905     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8906     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8907     { 0 }
8908 };
8909 static const struct message sl_edit_killfocus[] =
8910 {
8911     { HCBT_SETFOCUS, hook },
8912     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8913     { WM_KILLFOCUS, sent|wparam, 0 },
8914     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8915     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8916     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8917     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8918     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8919     { 0 }
8920 };
8921 static const struct message sl_edit_lbutton_dblclk[] =
8922 {
8923     { WM_LBUTTONDBLCLK, sent },
8924     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8925     { 0 }
8926 };
8927 static const struct message sl_edit_lbutton_down[] =
8928 {
8929     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8930     { HCBT_SETFOCUS, hook },
8931     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8932     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8933     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8934     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8935     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8936     { WM_CTLCOLOREDIT, sent|parent },
8937     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8938     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8939     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8940     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8941     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8942     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8943     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8944     { WM_CTLCOLOREDIT, sent|parent|optional },
8945     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8946     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8947     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8948     { 0 }
8949 };
8950 static const struct message ml_edit_lbutton_down[] =
8951 {
8952     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8953     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8954     { HCBT_SETFOCUS, hook },
8955     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8956     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8957     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8958     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8959     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8960     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8961     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8962     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8963     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8964     { 0 }
8965 };
8966 static const struct message sl_edit_lbutton_up[] =
8967 {
8968     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8969     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8970     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8971     { WM_CAPTURECHANGED, sent|defwinproc },
8972     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8973     { 0 }
8974 };
8975 static const struct message ml_edit_lbutton_up[] =
8976 {
8977     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8978     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8979     { WM_CAPTURECHANGED, sent|defwinproc },
8980     { 0 }
8981 };
8982
8983 static WNDPROC old_edit_proc;
8984
8985 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8986 {
8987     static long defwndproc_counter = 0;
8988     LRESULT ret;
8989     struct recvd_message msg;
8990
8991     if (ignore_message( message )) return 0;
8992
8993     msg.hwnd = hwnd;
8994     msg.message = message;
8995     msg.flags = sent|wparam|lparam;
8996     if (defwndproc_counter) msg.flags |= defwinproc;
8997     msg.wParam = wParam;
8998     msg.lParam = lParam;
8999     msg.descr = "edit";
9000     add_message(&msg);
9001
9002     defwndproc_counter++;
9003     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9004     defwndproc_counter--;
9005
9006     return ret;
9007 }
9008
9009 static void subclass_edit(void)
9010 {
9011     WNDCLASSA cls;
9012
9013     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9014
9015     old_edit_proc = cls.lpfnWndProc;
9016
9017     cls.hInstance = GetModuleHandle(0);
9018     cls.lpfnWndProc = edit_hook_proc;
9019     cls.lpszClassName = "my_edit_class";
9020     UnregisterClass(cls.lpszClassName, cls.hInstance);
9021     if (!RegisterClassA(&cls)) assert(0);
9022 }
9023
9024 static void test_edit_messages(void)
9025 {
9026     HWND hwnd, parent;
9027     DWORD dlg_code;
9028
9029     subclass_edit();
9030     log_all_parent_messages++;
9031
9032     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9033                              100, 100, 200, 200, 0, 0, 0, NULL);
9034     ok (parent != 0, "Failed to create parent window\n");
9035
9036     /* test single line edit */
9037     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9038                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9039     ok(hwnd != 0, "Failed to create edit window\n");
9040
9041     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9042     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9043
9044     ShowWindow(hwnd, SW_SHOW);
9045     UpdateWindow(hwnd);
9046     SetFocus(0);
9047     flush_sequence();
9048
9049     SetFocus(hwnd);
9050     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9051
9052     SetFocus(0);
9053     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9054
9055     SetFocus(0);
9056     ReleaseCapture();
9057     flush_sequence();
9058
9059     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9060     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9061
9062     SetFocus(0);
9063     ReleaseCapture();
9064     flush_sequence();
9065
9066     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9067     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9068
9069     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9070     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9071
9072     DestroyWindow(hwnd);
9073
9074     /* test multiline edit */
9075     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9076                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9077     ok(hwnd != 0, "Failed to create edit window\n");
9078
9079     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9080     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9081        "wrong dlg_code %08x\n", dlg_code);
9082
9083     ShowWindow(hwnd, SW_SHOW);
9084     UpdateWindow(hwnd);
9085     SetFocus(0);
9086     flush_sequence();
9087
9088     SetFocus(hwnd);
9089     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9090
9091     SetFocus(0);
9092     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9093
9094     SetFocus(0);
9095     ReleaseCapture();
9096     flush_sequence();
9097
9098     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9099     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9100
9101     SetFocus(0);
9102     ReleaseCapture();
9103     flush_sequence();
9104
9105     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9106     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9107
9108     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9109     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9110
9111     DestroyWindow(hwnd);
9112     DestroyWindow(parent);
9113
9114     log_all_parent_messages--;
9115 }
9116
9117 /**************************** End of Edit test ******************************/
9118
9119 static const struct message WmKeyDownSkippedSeq[] =
9120 {
9121     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9122     { 0 }
9123 };
9124 static const struct message WmKeyDownWasDownSkippedSeq[] =
9125 {
9126     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9127     { 0 }
9128 };
9129 static const struct message WmKeyUpSkippedSeq[] =
9130 {
9131     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9132     { 0 }
9133 };
9134 static const struct message WmUserKeyUpSkippedSeq[] =
9135 {
9136     { WM_USER, sent },
9137     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9138     { 0 }
9139 };
9140
9141 #define EV_STOP 0
9142 #define EV_SENDMSG 1
9143 #define EV_ACK 2
9144
9145 struct peekmsg_info
9146 {
9147     HWND  hwnd;
9148     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9149 };
9150
9151 static DWORD CALLBACK send_msg_thread_2(void *param)
9152 {
9153     DWORD ret;
9154     struct peekmsg_info *info = param;
9155
9156     trace("thread: looping\n");
9157     SetEvent(info->hevent[EV_ACK]);
9158
9159     while (1)
9160     {
9161         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9162
9163         switch (ret)
9164         {
9165         case WAIT_OBJECT_0 + EV_STOP:
9166             trace("thread: exiting\n");
9167             return 0;
9168
9169         case WAIT_OBJECT_0 + EV_SENDMSG:
9170             trace("thread: sending message\n");
9171             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
9172                 "SendNotifyMessageA failed error %u\n", GetLastError());
9173             SetEvent(info->hevent[EV_ACK]);
9174             break;
9175
9176         default:
9177             trace("unexpected return: %04x\n", ret);
9178             assert(0);
9179             break;
9180         }
9181     }
9182     return 0;
9183 }
9184
9185 static void test_PeekMessage(void)
9186 {
9187     MSG msg;
9188     HANDLE hthread;
9189     DWORD tid, qstatus;
9190     UINT qs_all_input = QS_ALLINPUT;
9191     UINT qs_input = QS_INPUT;
9192     BOOL ret;
9193     struct peekmsg_info info;
9194
9195     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9196                               100, 100, 200, 200, 0, 0, 0, NULL);
9197     assert(info.hwnd);
9198     ShowWindow(info.hwnd, SW_SHOW);
9199     UpdateWindow(info.hwnd);
9200     SetFocus(info.hwnd);
9201
9202     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9203     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9204     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9205
9206     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9207     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9208
9209     flush_events();
9210     flush_sequence();
9211
9212     SetLastError(0xdeadbeef);
9213     qstatus = GetQueueStatus(qs_all_input);
9214     if (GetLastError() == ERROR_INVALID_FLAGS)
9215     {
9216         trace("QS_RAWINPUT not supported on this platform\n");
9217         qs_all_input &= ~QS_RAWINPUT;
9218         qs_input &= ~QS_RAWINPUT;
9219     }
9220     if (qstatus & QS_POSTMESSAGE)
9221     {
9222         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9223         qstatus = GetQueueStatus(qs_all_input);
9224     }
9225     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9226
9227     trace("signalling to send message\n");
9228     SetEvent(info.hevent[EV_SENDMSG]);
9229     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9230
9231     /* pass invalid QS_xxxx flags */
9232     SetLastError(0xdeadbeef);
9233     qstatus = GetQueueStatus(0xffffffff);
9234     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9235     if (!qstatus)
9236     {
9237         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9238         qstatus = GetQueueStatus(qs_all_input);
9239     }
9240     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9241     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9242        "wrong qstatus %08x\n", qstatus);
9243
9244     msg.message = 0;
9245     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9246     ok(!ret,
9247        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9248         msg.message);
9249     ok_sequence(WmUser, "WmUser", FALSE);
9250
9251     qstatus = GetQueueStatus(qs_all_input);
9252     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9253
9254     keybd_event('N', 0, 0, 0);
9255     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9256     qstatus = GetQueueStatus(qs_all_input);
9257     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9258     {
9259         skip( "queuing key events not supported\n" );
9260         goto done;
9261     }
9262     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
9263        "wrong qstatus %08x\n", qstatus);
9264
9265     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9266     qstatus = GetQueueStatus(qs_all_input);
9267     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9268        "wrong qstatus %08x\n", qstatus);
9269
9270     InvalidateRect(info.hwnd, NULL, FALSE);
9271     qstatus = GetQueueStatus(qs_all_input);
9272     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9273        "wrong qstatus %08x\n", qstatus);
9274
9275     trace("signalling to send message\n");
9276     SetEvent(info.hevent[EV_SENDMSG]);
9277     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9278
9279     qstatus = GetQueueStatus(qs_all_input);
9280     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9281        "wrong qstatus %08x\n", qstatus);
9282
9283     msg.message = 0;
9284     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9285     if (ret && msg.message == WM_CHAR)
9286     {
9287         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9288         goto done;
9289     }
9290     ok(!ret,
9291        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9292         msg.message);
9293     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9294     {
9295         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9296         goto done;
9297     }
9298     ok_sequence(WmUser, "WmUser", FALSE);
9299
9300     qstatus = GetQueueStatus(qs_all_input);
9301     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9302        "wrong qstatus %08x\n", qstatus);
9303
9304     trace("signalling to send message\n");
9305     SetEvent(info.hevent[EV_SENDMSG]);
9306     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9307
9308     qstatus = GetQueueStatus(qs_all_input);
9309     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9310        "wrong qstatus %08x\n", qstatus);
9311
9312     msg.message = 0;
9313     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9314     ok(!ret,
9315        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9316         msg.message);
9317     ok_sequence(WmUser, "WmUser", FALSE);
9318
9319     qstatus = GetQueueStatus(qs_all_input);
9320     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9321        "wrong qstatus %08x\n", qstatus);
9322
9323     msg.message = 0;
9324     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9325     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9326        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9327        ret, msg.message, msg.wParam);
9328     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9329
9330     qstatus = GetQueueStatus(qs_all_input);
9331     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9332        "wrong qstatus %08x\n", qstatus);
9333
9334     msg.message = 0;
9335     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9336     ok(!ret,
9337        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9338         msg.message);
9339     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9340
9341     qstatus = GetQueueStatus(qs_all_input);
9342     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9343        "wrong qstatus %08x\n", qstatus);
9344
9345     msg.message = 0;
9346     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9347     ok(ret && msg.message == WM_PAINT,
9348        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9349     DispatchMessageA(&msg);
9350     ok_sequence(WmPaint, "WmPaint", FALSE);
9351
9352     qstatus = GetQueueStatus(qs_all_input);
9353     ok(qstatus == MAKELONG(0, QS_KEY),
9354        "wrong qstatus %08x\n", qstatus);
9355
9356     msg.message = 0;
9357     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9358     ok(!ret,
9359        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9360         msg.message);
9361     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9362
9363     qstatus = GetQueueStatus(qs_all_input);
9364     ok(qstatus == MAKELONG(0, QS_KEY),
9365        "wrong qstatus %08x\n", qstatus);
9366
9367     trace("signalling to send message\n");
9368     SetEvent(info.hevent[EV_SENDMSG]);
9369     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9370
9371     qstatus = GetQueueStatus(qs_all_input);
9372     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9373        "wrong qstatus %08x\n", qstatus);
9374
9375     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9376
9377     qstatus = GetQueueStatus(qs_all_input);
9378     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9379        "wrong qstatus %08x\n", qstatus);
9380
9381     msg.message = 0;
9382     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9383     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9384        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9385        ret, msg.message, msg.wParam);
9386     ok_sequence(WmUser, "WmUser", FALSE);
9387
9388     qstatus = GetQueueStatus(qs_all_input);
9389     ok(qstatus == MAKELONG(0, QS_KEY),
9390        "wrong qstatus %08x\n", qstatus);
9391
9392     msg.message = 0;
9393     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9394     ok(!ret,
9395        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9396         msg.message);
9397     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9398
9399     qstatus = GetQueueStatus(qs_all_input);
9400     ok(qstatus == MAKELONG(0, QS_KEY),
9401        "wrong qstatus %08x\n", qstatus);
9402
9403     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9404
9405     qstatus = GetQueueStatus(qs_all_input);
9406     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9407        "wrong qstatus %08x\n", qstatus);
9408
9409     trace("signalling to send message\n");
9410     SetEvent(info.hevent[EV_SENDMSG]);
9411     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9412
9413     qstatus = GetQueueStatus(qs_all_input);
9414     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9415        "wrong qstatus %08x\n", qstatus);
9416
9417     msg.message = 0;
9418     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9419     ok(!ret,
9420        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9421         msg.message);
9422     ok_sequence(WmUser, "WmUser", FALSE);
9423
9424     qstatus = GetQueueStatus(qs_all_input);
9425     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9426        "wrong qstatus %08x\n", qstatus);
9427
9428     msg.message = 0;
9429     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9430         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9431     else /* workaround for a missing QS_RAWINPUT support */
9432         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9433     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9434        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9435        ret, msg.message, msg.wParam);
9436     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9437
9438     qstatus = GetQueueStatus(qs_all_input);
9439     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9440        "wrong qstatus %08x\n", qstatus);
9441
9442     msg.message = 0;
9443     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9444         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9445     else /* workaround for a missing QS_RAWINPUT support */
9446         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9447     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9448        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9449        ret, msg.message, msg.wParam);
9450     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9451
9452     qstatus = GetQueueStatus(qs_all_input);
9453     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9454        "wrong qstatus %08x\n", qstatus);
9455
9456     msg.message = 0;
9457     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9458     ok(!ret,
9459        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9460         msg.message);
9461     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9462
9463     qstatus = GetQueueStatus(qs_all_input);
9464     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9465        "wrong qstatus %08x\n", qstatus);
9466
9467     msg.message = 0;
9468     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9469     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9470        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9471        ret, msg.message, msg.wParam);
9472     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9473
9474     qstatus = GetQueueStatus(qs_all_input);
9475     ok(qstatus == 0,
9476        "wrong qstatus %08x\n", qstatus);
9477
9478     msg.message = 0;
9479     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9480     ok(!ret,
9481        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9482         msg.message);
9483     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9484
9485     qstatus = GetQueueStatus(qs_all_input);
9486     ok(qstatus == 0,
9487        "wrong qstatus %08x\n", qstatus);
9488
9489     /* test whether presence of the quit flag in the queue affects
9490      * the queue state
9491      */
9492     PostQuitMessage(0x1234abcd);
9493
9494     qstatus = GetQueueStatus(qs_all_input);
9495     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9496        "wrong qstatus %08x\n", qstatus);
9497
9498     PostMessageA(info.hwnd, WM_USER, 0, 0);
9499
9500     qstatus = GetQueueStatus(qs_all_input);
9501     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9502        "wrong qstatus %08x\n", qstatus);
9503
9504     msg.message = 0;
9505     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9506     ok(ret && msg.message == WM_USER,
9507        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9508     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9509
9510     qstatus = GetQueueStatus(qs_all_input);
9511     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9512        "wrong qstatus %08x\n", qstatus);
9513
9514     msg.message = 0;
9515     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9516     ok(ret && msg.message == WM_QUIT,
9517        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9518     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9519     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9520     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9521
9522     qstatus = GetQueueStatus(qs_all_input);
9523 todo_wine {
9524     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9525        "wrong qstatus %08x\n", qstatus);
9526 }
9527
9528     msg.message = 0;
9529     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9530     ok(!ret,
9531        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9532         msg.message);
9533     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9534
9535     qstatus = GetQueueStatus(qs_all_input);
9536     ok(qstatus == 0,
9537        "wrong qstatus %08x\n", qstatus);
9538
9539     /* some GetMessage tests */
9540
9541     keybd_event('N', 0, 0, 0);
9542     qstatus = GetQueueStatus(qs_all_input);
9543     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9544
9545     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9546     qstatus = GetQueueStatus(qs_all_input);
9547     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9548
9549     if (qstatus)
9550     {
9551         ret = GetMessageA( &msg, 0, 0, 0 );
9552         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9553            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9554            ret, msg.message, msg.wParam);
9555         qstatus = GetQueueStatus(qs_all_input);
9556         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9557     }
9558
9559     if (qstatus)
9560     {
9561         ret = GetMessageA( &msg, 0, 0, 0 );
9562         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9563            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9564            ret, msg.message, msg.wParam);
9565         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9566         qstatus = GetQueueStatus(qs_all_input);
9567         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9568     }
9569
9570     keybd_event('N', 0, 0, 0);
9571     qstatus = GetQueueStatus(qs_all_input);
9572     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9573
9574     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9575     qstatus = GetQueueStatus(qs_all_input);
9576     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9577
9578     if (qstatus & (QS_KEY << 16))
9579     {
9580         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9581         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9582            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9583            ret, msg.message, msg.wParam);
9584         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9585         qstatus = GetQueueStatus(qs_all_input);
9586         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9587     }
9588
9589     if (qstatus)
9590     {
9591         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9592         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9593            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9594            ret, msg.message, msg.wParam);
9595         qstatus = GetQueueStatus(qs_all_input);
9596         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9597     }
9598
9599     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9600     qstatus = GetQueueStatus(qs_all_input);
9601     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9602
9603     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9604     qstatus = GetQueueStatus(qs_all_input);
9605     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9606
9607     trace("signalling to send message\n");
9608     SetEvent(info.hevent[EV_SENDMSG]);
9609     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9610     qstatus = GetQueueStatus(qs_all_input);
9611     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9612        "wrong qstatus %08x\n", qstatus);
9613
9614     if (qstatus & (QS_KEY << 16))
9615     {
9616         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9617         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9618            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9619            ret, msg.message, msg.wParam);
9620         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9621         qstatus = GetQueueStatus(qs_all_input);
9622         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9623     }
9624
9625     if (qstatus)
9626     {
9627         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9628         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9629            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9630            ret, msg.message, msg.wParam);
9631         qstatus = GetQueueStatus(qs_all_input);
9632         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9633     }
9634 done:
9635     trace("signalling to exit\n");
9636     SetEvent(info.hevent[EV_STOP]);
9637
9638     WaitForSingleObject(hthread, INFINITE);
9639
9640     CloseHandle(hthread);
9641     CloseHandle(info.hevent[0]);
9642     CloseHandle(info.hevent[1]);
9643     CloseHandle(info.hevent[2]);
9644
9645     DestroyWindow(info.hwnd);
9646 }
9647
9648 static void wait_move_event(HWND hwnd, int x, int y)
9649 {
9650     MSG msg;
9651     DWORD time;
9652     BOOL  ret;
9653     int go = 0;
9654
9655     time = GetTickCount();
9656     while (GetTickCount() - time < 200 && !go) {
9657         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9658         go  = ret && msg.pt.x > x && msg.pt.y > y;
9659         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9660     }
9661 }
9662
9663 #define STEP 5
9664 static void test_PeekMessage2(void)
9665 {
9666     HWND hwnd;
9667     BOOL ret;
9668     MSG msg;
9669     UINT message;
9670     DWORD time1, time2, time3;
9671     int x1, y1, x2, y2, x3, y3;
9672     POINT pos;
9673
9674     time1 = time2 = time3 = 0;
9675     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9676
9677     /* Initialise window and make sure it is ready for events */
9678     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9679                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9680     assert(hwnd);
9681     trace("Window for test_PeekMessage2 %p\n", hwnd);
9682     ShowWindow(hwnd, SW_SHOW);
9683     UpdateWindow(hwnd);
9684     SetFocus(hwnd);
9685     GetCursorPos(&pos);
9686     SetCursorPos(100, 100);
9687     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9688     flush_events();
9689
9690     /* Do initial mousemove, wait until we can see it
9691        and then do our test peek with PM_NOREMOVE. */
9692     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9693     wait_move_event(hwnd, 100-STEP, 100-STEP);
9694
9695     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9696     if (!ret)
9697     {
9698         skip( "queuing mouse events not supported\n" );
9699         goto done;
9700     }
9701     else
9702     {
9703         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9704         message = msg.message;
9705         time1 = msg.time;
9706         x1 = msg.pt.x;
9707         y1 = msg.pt.y;
9708         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9709     }
9710
9711     /* Allow time to advance a bit, and then simulate the user moving their
9712      * mouse around. After that we peek again with PM_NOREMOVE.
9713      * Although the previous mousemove message was never removed, the
9714      * mousemove we now peek should reflect the recent mouse movements
9715      * because the input queue will merge the move events. */
9716     Sleep(100);
9717     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9718     wait_move_event(hwnd, x1, y1);
9719
9720     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9721     ok(ret, "no message available\n");
9722     if (ret) {
9723         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9724         message = msg.message;
9725         time2 = msg.time;
9726         x2 = msg.pt.x;
9727         y2 = msg.pt.y;
9728         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9729         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9730         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9731     }
9732
9733     /* Have another go, to drive the point home */
9734     Sleep(100);
9735     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9736     wait_move_event(hwnd, x2, y2);
9737
9738     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9739     ok(ret, "no message available\n");
9740     if (ret) {
9741         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9742         message = msg.message;
9743         time3 = msg.time;
9744         x3 = msg.pt.x;
9745         y3 = msg.pt.y;
9746         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9747         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9748         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9749     }
9750
9751 done:
9752     DestroyWindow(hwnd);
9753     SetCursorPos(pos.x, pos.y);
9754     flush_events();
9755 }
9756
9757 static void test_quit_message(void)
9758 {
9759     MSG msg;
9760     BOOL ret;
9761
9762     /* test using PostQuitMessage */
9763     flush_events();
9764     PostQuitMessage(0xbeef);
9765
9766     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9767     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9768     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9769     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9770
9771     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9772     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9773
9774     ret = GetMessage(&msg, NULL, 0, 0);
9775     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9776     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9777
9778     /* note: WM_QUIT message received after WM_USER message */
9779     ret = GetMessage(&msg, NULL, 0, 0);
9780     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9781     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9782     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9783
9784     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9785     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9786
9787     /* now test with PostThreadMessage - different behaviour! */
9788     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9789
9790     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9791     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9792     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9793     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9794
9795     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9796     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9797
9798     /* note: we receive the WM_QUIT message first this time */
9799     ret = GetMessage(&msg, NULL, 0, 0);
9800     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9801     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9802     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9803
9804     ret = GetMessage(&msg, NULL, 0, 0);
9805     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9806     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9807 }
9808
9809 static const struct message WmMouseHoverSeq[] = {
9810     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9811     { WM_MOUSEACTIVATE, sent|optional },
9812     { WM_TIMER, sent|optional }, /* XP sends it */
9813     { WM_SYSTIMER, sent },
9814     { WM_MOUSEHOVER, sent|wparam, 0 },
9815     { 0 }
9816 };
9817
9818 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9819 {
9820     MSG msg;
9821     DWORD start_ticks, end_ticks;
9822
9823     start_ticks = GetTickCount();
9824     /* add some deviation (50%) to cover not expected delays */
9825     start_ticks += timeout / 2;
9826
9827     do
9828     {
9829         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9830         {
9831             /* Timer proc messages are not dispatched to the window proc,
9832              * and therefore not logged.
9833              */
9834             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9835             {
9836                 struct recvd_message s_msg;
9837
9838                 s_msg.hwnd = msg.hwnd;
9839                 s_msg.message = msg.message;
9840                 s_msg.flags = sent|wparam|lparam;
9841                 s_msg.wParam = msg.wParam;
9842                 s_msg.lParam = msg.lParam;
9843                 s_msg.descr = "msg_loop";
9844                 add_message(&s_msg);
9845             }
9846             DispatchMessage(&msg);
9847         }
9848
9849         end_ticks = GetTickCount();
9850
9851         /* inject WM_MOUSEMOVE to see how it changes tracking */
9852         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9853         {
9854             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9855             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9856
9857             inject_mouse_move = FALSE;
9858         }
9859     } while (start_ticks + timeout >= end_ticks);
9860 }
9861
9862 static void test_TrackMouseEvent(void)
9863 {
9864     TRACKMOUSEEVENT tme;
9865     BOOL ret;
9866     HWND hwnd, hchild;
9867     RECT rc_parent, rc_child;
9868     UINT default_hover_time, hover_width = 0, hover_height = 0;
9869
9870 #define track_hover(track_hwnd, track_hover_time) \
9871     tme.cbSize = sizeof(tme); \
9872     tme.dwFlags = TME_HOVER; \
9873     tme.hwndTrack = track_hwnd; \
9874     tme.dwHoverTime = track_hover_time; \
9875     SetLastError(0xdeadbeef); \
9876     ret = pTrackMouseEvent(&tme); \
9877     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9878
9879 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9880     tme.cbSize = sizeof(tme); \
9881     tme.dwFlags = TME_QUERY; \
9882     tme.hwndTrack = (HWND)0xdeadbeef; \
9883     tme.dwHoverTime = 0xdeadbeef; \
9884     SetLastError(0xdeadbeef); \
9885     ret = pTrackMouseEvent(&tme); \
9886     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9887     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9888     ok(tme.dwFlags == (expected_track_flags), \
9889        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9890     ok(tme.hwndTrack == (expected_track_hwnd), \
9891        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9892     ok(tme.dwHoverTime == (expected_hover_time), \
9893        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9894
9895 #define track_hover_cancel(track_hwnd) \
9896     tme.cbSize = sizeof(tme); \
9897     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9898     tme.hwndTrack = track_hwnd; \
9899     tme.dwHoverTime = 0xdeadbeef; \
9900     SetLastError(0xdeadbeef); \
9901     ret = pTrackMouseEvent(&tme); \
9902     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9903
9904     default_hover_time = 0xdeadbeef;
9905     SetLastError(0xdeadbeef);
9906     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9907     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9908        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9909     if (!ret) default_hover_time = 400;
9910     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9911
9912     SetLastError(0xdeadbeef);
9913     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9914     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9915        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9916     if (!ret) hover_width = 4;
9917     SetLastError(0xdeadbeef);
9918     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9919     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9920        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9921     if (!ret) hover_height = 4;
9922     trace("hover rect is %u x %d\n", hover_width, hover_height);
9923
9924     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9925                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9926                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9927                           NULL, NULL, 0);
9928     assert(hwnd);
9929
9930     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9931                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9932                           50, 50, 200, 200, hwnd,
9933                           NULL, NULL, 0);
9934     assert(hchild);
9935
9936     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9937     flush_events();
9938     flush_sequence();
9939
9940     tme.cbSize = 0;
9941     tme.dwFlags = TME_QUERY;
9942     tme.hwndTrack = (HWND)0xdeadbeef;
9943     tme.dwHoverTime = 0xdeadbeef;
9944     SetLastError(0xdeadbeef);
9945     ret = pTrackMouseEvent(&tme);
9946     ok(!ret, "TrackMouseEvent should fail\n");
9947     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9948        "not expected error %u\n", GetLastError());
9949
9950     tme.cbSize = sizeof(tme);
9951     tme.dwFlags = TME_HOVER;
9952     tme.hwndTrack = (HWND)0xdeadbeef;
9953     tme.dwHoverTime = 0xdeadbeef;
9954     SetLastError(0xdeadbeef);
9955     ret = pTrackMouseEvent(&tme);
9956     ok(!ret, "TrackMouseEvent should fail\n");
9957     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9958        "not expected error %u\n", GetLastError());
9959
9960     tme.cbSize = sizeof(tme);
9961     tme.dwFlags = TME_HOVER | TME_CANCEL;
9962     tme.hwndTrack = (HWND)0xdeadbeef;
9963     tme.dwHoverTime = 0xdeadbeef;
9964     SetLastError(0xdeadbeef);
9965     ret = pTrackMouseEvent(&tme);
9966     ok(!ret, "TrackMouseEvent should fail\n");
9967     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9968        "not expected error %u\n", GetLastError());
9969
9970     GetWindowRect(hwnd, &rc_parent);
9971     GetWindowRect(hchild, &rc_child);
9972     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9973
9974     /* Process messages so that the system updates its internal current
9975      * window and hittest, otherwise TrackMouseEvent calls don't have any
9976      * effect.
9977      */
9978     flush_events();
9979     flush_sequence();
9980
9981     track_query(0, NULL, 0);
9982     track_hover(hchild, 0);
9983     track_query(0, NULL, 0);
9984
9985     flush_events();
9986     flush_sequence();
9987
9988     track_hover(hwnd, 0);
9989     tme.cbSize = sizeof(tme);
9990     tme.dwFlags = TME_QUERY;
9991     tme.hwndTrack = (HWND)0xdeadbeef;
9992     tme.dwHoverTime = 0xdeadbeef;
9993     SetLastError(0xdeadbeef);
9994     ret = pTrackMouseEvent(&tme);
9995     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
9996     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
9997     if (!tme.dwFlags)
9998     {
9999         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10000         DestroyWindow( hwnd );
10001         return;
10002     }
10003     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10004     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10005     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10006        tme.dwHoverTime, default_hover_time);
10007
10008     pump_msg_loop_timeout(default_hover_time, FALSE);
10009     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10010
10011     track_query(0, NULL, 0);
10012
10013     track_hover(hwnd, HOVER_DEFAULT);
10014     track_query(TME_HOVER, hwnd, default_hover_time);
10015
10016     Sleep(default_hover_time / 2);
10017     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10018     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10019
10020     track_query(TME_HOVER, hwnd, default_hover_time);
10021
10022     pump_msg_loop_timeout(default_hover_time, FALSE);
10023     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10024
10025     track_query(0, NULL, 0);
10026
10027     track_hover(hwnd, HOVER_DEFAULT);
10028     track_query(TME_HOVER, hwnd, default_hover_time);
10029
10030     pump_msg_loop_timeout(default_hover_time, TRUE);
10031     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10032
10033     track_query(0, NULL, 0);
10034
10035     track_hover(hwnd, HOVER_DEFAULT);
10036     track_query(TME_HOVER, hwnd, default_hover_time);
10037     track_hover_cancel(hwnd);
10038
10039     DestroyWindow(hwnd);
10040
10041 #undef track_hover
10042 #undef track_query
10043 #undef track_hover_cancel
10044 }
10045
10046
10047 static const struct message WmSetWindowRgn[] = {
10048     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10049     { WM_NCCALCSIZE, sent|wparam, 1 },
10050     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10051     { WM_GETTEXT, sent|defwinproc|optional },
10052     { WM_ERASEBKGND, sent|optional },
10053     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10054     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10055     { 0 }
10056 };
10057
10058 static const struct message WmSetWindowRgn_no_redraw[] = {
10059     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10060     { WM_NCCALCSIZE, sent|wparam, 1 },
10061     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10062     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10063     { 0 }
10064 };
10065
10066 static const struct message WmSetWindowRgn_clear[] = {
10067     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10068     { WM_NCCALCSIZE, sent|wparam, 1 },
10069     { WM_NCPAINT, sent|optional },
10070     { WM_GETTEXT, sent|defwinproc|optional },
10071     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10072     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10073     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10074     { WM_NCPAINT, sent|optional },
10075     { WM_GETTEXT, sent|defwinproc|optional },
10076     { WM_ERASEBKGND, sent|optional },
10077     { WM_WINDOWPOSCHANGING, sent|optional },
10078     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10079     { WM_NCPAINT, sent|optional },
10080     { WM_GETTEXT, sent|defwinproc|optional },
10081     { WM_ERASEBKGND, sent|optional },
10082     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10083     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10084     { WM_NCPAINT, sent|optional },
10085     { WM_GETTEXT, sent|defwinproc|optional },
10086     { WM_ERASEBKGND, sent|optional },
10087     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10088     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10089     { 0 }
10090 };
10091
10092 static void test_SetWindowRgn(void)
10093 {
10094     HRGN hrgn;
10095     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10096                                 100, 100, 200, 200, 0, 0, 0, NULL);
10097     ok( hwnd != 0, "Failed to create overlapped window\n" );
10098
10099     ShowWindow( hwnd, SW_SHOW );
10100     UpdateWindow( hwnd );
10101     flush_events();
10102     flush_sequence();
10103
10104     trace("testing SetWindowRgn\n");
10105     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10106     SetWindowRgn( hwnd, hrgn, TRUE );
10107     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10108
10109     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10110     SetWindowRgn( hwnd, hrgn, FALSE );
10111     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10112
10113     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10114     SetWindowRgn( hwnd, hrgn, TRUE );
10115     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10116
10117     SetWindowRgn( hwnd, 0, TRUE );
10118     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10119
10120     DestroyWindow( hwnd );
10121 }
10122
10123 /*************************** ShowWindow() test ******************************/
10124 static const struct message WmShowNormal[] = {
10125     { WM_SHOWWINDOW, sent|wparam, 1 },
10126     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10127     { HCBT_ACTIVATE, hook },
10128     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10129     { HCBT_SETFOCUS, hook },
10130     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10131     { 0 }
10132 };
10133 static const struct message WmShow[] = {
10134     { WM_SHOWWINDOW, sent|wparam, 1 },
10135     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10136     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10137     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10138     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10139     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10140     { 0 }
10141 };
10142 static const struct message WmShowNoActivate_1[] = {
10143     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10144     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10145     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10146     { WM_MOVE, sent|defwinproc|optional },
10147     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10148     { 0 }
10149 };
10150 static const struct message WmShowNoActivate_2[] = {
10151     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10153     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10154     { WM_MOVE, sent|defwinproc },
10155     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10156     { HCBT_SETFOCUS, hook|optional },
10157     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10158     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10159     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10160     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10161     { 0 }
10162 };
10163 static const struct message WmShowNA_1[] = {
10164     { WM_SHOWWINDOW, sent|wparam, 1 },
10165     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10166     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10167     { 0 }
10168 };
10169 static const struct message WmShowNA_2[] = {
10170     { WM_SHOWWINDOW, sent|wparam, 1 },
10171     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10172     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10173     { 0 }
10174 };
10175 static const struct message WmRestore_1[] = {
10176     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10177     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10178     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10179     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10180     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10181     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10182     { WM_MOVE, sent|defwinproc },
10183     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10184     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10185     { 0 }
10186 };
10187 static const struct message WmRestore_2[] = {
10188     { WM_SHOWWINDOW, sent|wparam, 1 },
10189     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10190     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10191     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10192     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10193     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10194     { 0 }
10195 };
10196 static const struct message WmRestore_3[] = {
10197     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10198     { WM_GETMINMAXINFO, sent },
10199     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10200     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10201     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10202     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10203     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10204     { WM_MOVE, sent|defwinproc },
10205     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10206     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10207     { 0 }
10208 };
10209 static const struct message WmRestore_4[] = {
10210     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10211     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10212     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10213     { WM_MOVE, sent|defwinproc|optional },
10214     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10215     { 0 }
10216 };
10217 static const struct message WmRestore_5[] = {
10218     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10219     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10220     { HCBT_ACTIVATE, hook|optional },
10221     { HCBT_SETFOCUS, hook|optional },
10222     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10223     { WM_MOVE, sent|defwinproc|optional },
10224     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10225     { 0 }
10226 };
10227 static const struct message WmHide_1[] = {
10228     { WM_SHOWWINDOW, sent|wparam, 0 },
10229     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10230     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10231     { HCBT_ACTIVATE, hook|optional },
10232     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10233     { 0 }
10234 };
10235 static const struct message WmHide_2[] = {
10236     { WM_SHOWWINDOW, sent|wparam, 0 },
10237     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10238     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10239     { HCBT_ACTIVATE, hook|optional },
10240     { 0 }
10241 };
10242 static const struct message WmHide_3[] = {
10243     { WM_SHOWWINDOW, sent|wparam, 0 },
10244     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10245     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10246     { HCBT_SETFOCUS, hook|optional },
10247     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10248     { 0 }
10249 };
10250 static const struct message WmShowMinimized_1[] = {
10251     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10252     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10253     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10254     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10255     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10256     { WM_MOVE, sent|defwinproc },
10257     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10258     { 0 }
10259 };
10260 static const struct message WmMinimize_1[] = {
10261     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10262     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10263     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10264     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10265     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10266     { WM_MOVE, sent|defwinproc },
10267     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10268     { 0 }
10269 };
10270 static const struct message WmMinimize_2[] = {
10271     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10272     { HCBT_SETFOCUS, hook|optional },
10273     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10274     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10275     { WM_MOVE, sent|defwinproc },
10276     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10277     { 0 }
10278 };
10279 static const struct message WmMinimize_3[] = {
10280     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10281     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10282     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10283     { WM_MOVE, sent|defwinproc },
10284     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10285     { 0 }
10286 };
10287 static const struct message WmShowMinNoActivate[] = {
10288     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10289     { WM_WINDOWPOSCHANGING, sent },
10290     { WM_WINDOWPOSCHANGED, sent },
10291     { WM_MOVE, sent|defwinproc|optional },
10292     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10293     { 0 }
10294 };
10295 static const struct message WmMinMax_1[] = {
10296     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10297     { 0 }
10298 };
10299 static const struct message WmMinMax_2[] = {
10300     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10301     { WM_GETMINMAXINFO, sent|optional },
10302     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10303     { HCBT_ACTIVATE, hook|optional },
10304     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10305     { HCBT_SETFOCUS, hook|optional },
10306     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10307     { WM_MOVE, sent|defwinproc|optional },
10308     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10309     { HCBT_SETFOCUS, hook|optional },
10310     { 0 }
10311 };
10312 static const struct message WmMinMax_3[] = {
10313     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10314     { HCBT_SETFOCUS, hook|optional },
10315     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10316     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10317     { WM_MOVE, sent|defwinproc|optional },
10318     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10319     { 0 }
10320 };
10321 static const struct message WmMinMax_4[] = {
10322     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10323     { 0 }
10324 };
10325 static const struct message WmShowMaximized_1[] = {
10326     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10327     { WM_GETMINMAXINFO, sent },
10328     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10329     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10330     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10331     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10332     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10333     { WM_MOVE, sent|defwinproc },
10334     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10335     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10336     { 0 }
10337 };
10338 static const struct message WmShowMaximized_2[] = {
10339     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10340     { WM_GETMINMAXINFO, sent },
10341     { WM_WINDOWPOSCHANGING, sent|optional },
10342     { HCBT_ACTIVATE, hook|optional },
10343     { WM_WINDOWPOSCHANGED, sent|optional },
10344     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10345     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10346     { WM_WINDOWPOSCHANGING, sent|optional },
10347     { HCBT_SETFOCUS, hook|optional },
10348     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10349     { WM_MOVE, sent|defwinproc },
10350     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10351     { HCBT_SETFOCUS, hook|optional },
10352     { 0 }
10353 };
10354 static const struct message WmShowMaximized_3[] = {
10355     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10356     { WM_GETMINMAXINFO, sent|optional },
10357     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10358     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10359     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10360     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10361     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10362     { WM_MOVE, sent|defwinproc|optional },
10363     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10364     { 0 }
10365 };
10366
10367 static void test_ShowWindow(void)
10368 {
10369     /* ShowWindow commands in random order */
10370     static const struct
10371     {
10372         INT cmd; /* ShowWindow command */
10373         LPARAM ret; /* ShowWindow return value */
10374         DWORD style; /* window style after the command */
10375         const struct message *msg; /* message sequence the command produces */
10376         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10377     } sw[] =
10378     {
10379 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10380 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10381 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10382 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10383 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10384 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10385 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10386 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10387 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10388 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10389 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10390 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10391 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10392 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10393 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10394 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10395 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10396 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10397 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10398 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10399 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10400 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10401 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10402 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10403 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10404 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10405 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10406 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10407 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10408 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10409 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10410 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10411 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10412 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10413 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10414 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10415 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10416 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10417 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10418 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10419 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10420 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE },
10421 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10422 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10423 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10424 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10425 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10426 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10427 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10428 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10429 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10430 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10431 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10432 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10433 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10434 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10435 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10436     };
10437     HWND hwnd;
10438     DWORD style;
10439     LPARAM ret;
10440     INT i;
10441
10442 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10443     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10444                           120, 120, 90, 90,
10445                           0, 0, 0, NULL);
10446     assert(hwnd);
10447
10448     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10449     ok(style == 0, "expected style 0, got %08x\n", style);
10450
10451     flush_events();
10452     flush_sequence();
10453
10454     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10455     {
10456         static const char * const sw_cmd_name[13] =
10457         {
10458             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10459             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10460             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10461             "SW_NORMALNA" /* 0xCC */
10462         };
10463         char comment[64];
10464         INT idx; /* index into the above array of names */
10465
10466         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10467
10468         style = GetWindowLong(hwnd, GWL_STYLE);
10469         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10470         ret = ShowWindow(hwnd, sw[i].cmd);
10471         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10472         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10473         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10474
10475         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10476         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10477
10478         flush_events();
10479         flush_sequence();
10480     }
10481
10482     DestroyWindow(hwnd);
10483 }
10484
10485 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10486 {
10487     struct recvd_message msg;
10488
10489     if (ignore_message( message )) return 0;
10490
10491     msg.hwnd = hwnd;
10492     msg.message = message;
10493     msg.flags = sent|wparam|lparam;
10494     msg.wParam = wParam;
10495     msg.lParam = lParam;
10496     msg.descr = "dialog";
10497     add_message(&msg);
10498
10499     /* calling DefDlgProc leads to a recursion under XP */
10500
10501     switch (message)
10502     {
10503     case WM_INITDIALOG:
10504     case WM_GETDLGCODE:
10505         return 0;
10506     }
10507     return 1;
10508 }
10509
10510 static const struct message WmDefDlgSetFocus_1[] = {
10511     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10512     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10513     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10514     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10515     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10516     { HCBT_SETFOCUS, hook },
10517     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10518     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10519     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10520     { WM_SETFOCUS, sent|wparam, 0 },
10521     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10522     { WM_CTLCOLOREDIT, sent },
10523     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10524     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10525     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10526     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10527     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10528     { 0 }
10529 };
10530 static const struct message WmDefDlgSetFocus_2[] = {
10531     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10532     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10533     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10534     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10535     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10536     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10537     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10538     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10539     { 0 }
10540 };
10541 /* Creation of a dialog */
10542 static const struct message WmCreateDialogParamSeq_1[] = {
10543     { HCBT_CREATEWND, hook },
10544     { WM_NCCREATE, sent },
10545     { WM_NCCALCSIZE, sent|wparam, 0 },
10546     { WM_CREATE, sent },
10547     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10548     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10549     { WM_MOVE, sent },
10550     { WM_SETFONT, sent },
10551     { WM_INITDIALOG, sent },
10552     { WM_CHANGEUISTATE, sent|optional },
10553     { 0 }
10554 };
10555 /* Creation of a dialog */
10556 static const struct message WmCreateDialogParamSeq_2[] = {
10557     { HCBT_CREATEWND, hook },
10558     { WM_NCCREATE, sent },
10559     { WM_NCCALCSIZE, sent|wparam, 0 },
10560     { WM_CREATE, sent },
10561     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10562     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10563     { WM_MOVE, sent },
10564     { WM_CHANGEUISTATE, sent|optional },
10565     { 0 }
10566 };
10567
10568 static void test_dialog_messages(void)
10569 {
10570     WNDCLASS cls;
10571     HWND hdlg, hedit1, hedit2, hfocus;
10572     LRESULT ret;
10573
10574 #define set_selection(hctl, start, end) \
10575     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10576     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10577
10578 #define check_selection(hctl, start, end) \
10579     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10580     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10581
10582     subclass_edit();
10583
10584     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10585                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10586                           0, 0, 100, 100, 0, 0, 0, NULL);
10587     ok(hdlg != 0, "Failed to create custom dialog window\n");
10588
10589     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10590                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10591                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10592     ok(hedit1 != 0, "Failed to create edit control\n");
10593     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10594                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10595                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10596     ok(hedit2 != 0, "Failed to create edit control\n");
10597
10598     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10599     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10600
10601     hfocus = GetFocus();
10602     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10603
10604     SetFocus(hedit2);
10605     hfocus = GetFocus();
10606     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10607
10608     check_selection(hedit1, 0, 0);
10609     check_selection(hedit2, 0, 0);
10610
10611     set_selection(hedit2, 0, -1);
10612     check_selection(hedit2, 0, 3);
10613
10614     SetFocus(0);
10615     hfocus = GetFocus();
10616     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10617
10618     flush_sequence();
10619     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10620     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10621     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10622
10623     hfocus = GetFocus();
10624     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10625
10626     check_selection(hedit1, 0, 5);
10627     check_selection(hedit2, 0, 3);
10628
10629     flush_sequence();
10630     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10631     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10632     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10633
10634     hfocus = GetFocus();
10635     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10636
10637     check_selection(hedit1, 0, 5);
10638     check_selection(hedit2, 0, 3);
10639
10640     EndDialog(hdlg, 0);
10641     DestroyWindow(hedit1);
10642     DestroyWindow(hedit2);
10643     DestroyWindow(hdlg);
10644     flush_sequence();
10645
10646 #undef set_selection
10647 #undef check_selection
10648
10649     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10650     cls.lpszClassName = "MyDialogClass";
10651     cls.hInstance = GetModuleHandle(0);
10652     /* need a cast since a dlgproc is used as a wndproc */
10653     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10654     if (!RegisterClass(&cls)) assert(0);
10655
10656     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10657     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10658     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10659     EndDialog(hdlg, 0);
10660     DestroyWindow(hdlg);
10661     flush_sequence();
10662
10663     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10664     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10665     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10666     EndDialog(hdlg, 0);
10667     DestroyWindow(hdlg);
10668     flush_sequence();
10669
10670     UnregisterClass(cls.lpszClassName, cls.hInstance);
10671 }
10672
10673 static void test_nullCallback(void)
10674 {
10675     HWND hwnd;
10676
10677     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10678                            100, 100, 200, 200, 0, 0, 0, NULL);
10679     ok (hwnd != 0, "Failed to create overlapped window\n");
10680
10681     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10682     flush_events();
10683     DestroyWindow(hwnd);
10684 }
10685
10686 /* SetActiveWindow( 0 ) hwnd visible */
10687 static const struct message SetActiveWindowSeq0[] =
10688 {
10689     { HCBT_ACTIVATE, hook|optional },
10690     { WM_NCACTIVATE, sent|wparam, 0 },
10691     { WM_GETTEXT, sent|defwinproc|optional },
10692     { WM_ACTIVATE, sent|wparam, 0 },
10693     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10694     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10695     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10696     { WM_KILLFOCUS, sent|optional },
10697     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10698     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10699     { WM_NCACTIVATE, sent|wparam|optional, 1 },
10700     { WM_GETTEXT, sent|defwinproc|optional },
10701     { WM_ACTIVATE, sent|wparam|optional, 1 },
10702     { HCBT_SETFOCUS, hook|optional },
10703     { WM_KILLFOCUS, sent|defwinproc|optional },
10704     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10705     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10706     { WM_IME_SETCONTEXT, sent|optional },
10707     { WM_IME_SETCONTEXT, sent|optional },
10708     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10709     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10710     { WM_SETFOCUS, sent|defwinproc|optional },
10711     { WM_GETTEXT, sent|optional },
10712     { 0 }
10713 };
10714 /* SetActiveWindow( hwnd ) hwnd visible */
10715 static const struct message SetActiveWindowSeq1[] =
10716 {
10717     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10718     { 0 }
10719 };
10720 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10721 static const struct message SetActiveWindowSeq2[] =
10722 {
10723     { HCBT_ACTIVATE, hook },
10724     { WM_NCACTIVATE, sent|wparam, 0 },
10725     { WM_GETTEXT, sent|defwinproc|optional },
10726     { WM_ACTIVATE, sent|wparam, 0 },
10727     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10728     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10729     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10730     { WM_NCPAINT, sent|optional },
10731     { WM_GETTEXT, sent|defwinproc|optional },
10732     { WM_ERASEBKGND, sent|optional },
10733     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10734     { WM_NCACTIVATE, sent|wparam, 1 },
10735     { WM_GETTEXT, sent|defwinproc|optional },
10736     { WM_ACTIVATE, sent|wparam, 1 },
10737     { HCBT_SETFOCUS, hook },
10738     { WM_KILLFOCUS, sent|defwinproc },
10739     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10740     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10741     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10742     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10743     { WM_SETFOCUS, sent|defwinproc },
10744     { WM_GETTEXT, sent|optional },
10745     { 0 }
10746 };
10747
10748 /* SetActiveWindow( hwnd ) hwnd not visible */
10749 static const struct message SetActiveWindowSeq3[] =
10750 {
10751     { HCBT_ACTIVATE, hook },
10752     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10753     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10754     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10755     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10756     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10757     { WM_ACTIVATEAPP, sent|wparam, 1 },
10758     { WM_ACTIVATEAPP, sent|wparam, 1 },
10759     { WM_NCACTIVATE, sent|wparam, 1 },
10760     { WM_ACTIVATE, sent|wparam, 1 },
10761     { HCBT_SETFOCUS, hook },
10762     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10763     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10764     { WM_SETFOCUS, sent|defwinproc },
10765     { 0 }
10766 };
10767 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10768 static const struct message SetActiveWindowSeq4[] =
10769 {
10770     { HCBT_ACTIVATE, hook },
10771     { WM_NCACTIVATE, sent|wparam, 0 },
10772     { WM_GETTEXT, sent|defwinproc|optional },
10773     { WM_ACTIVATE, sent|wparam, 0 },
10774     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10775     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10776     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10777     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10778     { WM_NCACTIVATE, sent|wparam, 1 },
10779     { WM_GETTEXT, sent|defwinproc|optional },
10780     { WM_ACTIVATE, sent|wparam, 1 },
10781     { HCBT_SETFOCUS, hook },
10782     { WM_KILLFOCUS, sent|defwinproc },
10783     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10784     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10785     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10786     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10787     { WM_SETFOCUS, sent|defwinproc },
10788     { 0 }
10789 };
10790
10791
10792 static void test_SetActiveWindow(void)
10793 {
10794     HWND hwnd, popup, ret;
10795
10796     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10797                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10798                            100, 100, 200, 200, 0, 0, 0, NULL);
10799
10800     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10801                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10802                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10803
10804     ok(hwnd != 0, "Failed to create overlapped window\n");
10805     ok(popup != 0, "Failed to create popup window\n");
10806     SetForegroundWindow( popup );
10807     flush_sequence();
10808
10809     trace("SetActiveWindow(0)\n");
10810     ret = SetActiveWindow(0);
10811     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10812     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
10813     flush_sequence();
10814
10815     trace("SetActiveWindow(hwnd), hwnd visible\n");
10816     ret = SetActiveWindow(hwnd);
10817     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10818     flush_sequence();
10819
10820     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10821     ret = SetActiveWindow(popup);
10822     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10823     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10824     flush_sequence();
10825
10826     ShowWindow(hwnd, SW_HIDE);
10827     ShowWindow(popup, SW_HIDE);
10828     flush_sequence();
10829
10830     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10831     ret = SetActiveWindow(hwnd);
10832     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
10833     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10834     flush_sequence();
10835
10836     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10837     ret = SetActiveWindow(popup);
10838     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10839     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10840     flush_sequence();
10841
10842     trace("done\n");
10843
10844     DestroyWindow(hwnd);
10845 }
10846
10847 static const struct message SetForegroundWindowSeq[] =
10848 {
10849     { WM_NCACTIVATE, sent|wparam, 0 },
10850     { WM_GETTEXT, sent|defwinproc|optional },
10851     { WM_ACTIVATE, sent|wparam, 0 },
10852     { WM_ACTIVATEAPP, sent|wparam, 0 },
10853     { WM_KILLFOCUS, sent },
10854     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10855     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10856     { 0 }
10857 };
10858
10859 static void test_SetForegroundWindow(void)
10860 {
10861     HWND hwnd;
10862
10863     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10864                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10865                            100, 100, 200, 200, 0, 0, 0, NULL);
10866     ok (hwnd != 0, "Failed to create overlapped window\n");
10867     SetForegroundWindow( hwnd );
10868     flush_sequence();
10869
10870     trace("SetForegroundWindow( 0 )\n");
10871     SetForegroundWindow( 0 );
10872     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10873     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10874     SetForegroundWindow( GetDesktopWindow() );
10875     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10876                                         "foreground top level window", FALSE);
10877     trace("done\n");
10878
10879     DestroyWindow(hwnd);
10880 }
10881
10882 static void test_dbcs_wm_char(void)
10883 {
10884     BYTE dbch[2];
10885     WCHAR wch, bad_wch;
10886     HWND hwnd, hwnd2;
10887     MSG msg;
10888     DWORD time;
10889     POINT pt;
10890     DWORD_PTR res;
10891     CPINFOEXA cpinfo;
10892     UINT i, j, k;
10893     struct message wmCharSeq[2];
10894
10895     if (!pGetCPInfoExA)
10896     {
10897         win_skip("GetCPInfoExA is not available\n");
10898         return;
10899     }
10900
10901     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10902     if (cpinfo.MaxCharSize != 2)
10903     {
10904         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10905         return;
10906     }
10907
10908     dbch[0] = dbch[1] = 0;
10909     wch = 0;
10910     bad_wch = cpinfo.UnicodeDefaultChar;
10911     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10912         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10913             for (k = 128; k <= 255; k++)
10914             {
10915                 char str[2];
10916                 WCHAR wstr[2];
10917                 str[0] = j;
10918                 str[1] = k;
10919                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10920                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10921                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10922                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10923                 {
10924                     dbch[0] = j;
10925                     dbch[1] = k;
10926                     wch = wstr[0];
10927                     break;
10928                 }
10929             }
10930
10931     if (!wch)
10932     {
10933         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10934         return;
10935     }
10936     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10937            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10938
10939     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10940                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10941     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10942                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10943     ok (hwnd != 0, "Failed to create overlapped window\n");
10944     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10945     flush_sequence();
10946
10947     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10948     wmCharSeq[0].message = WM_CHAR;
10949     wmCharSeq[0].flags = sent|wparam;
10950     wmCharSeq[0].wParam = wch;
10951
10952     /* posted message */
10953     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10954     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10955     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10956     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10957     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10958     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10959     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10960
10961     /* posted thread message */
10962     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10963     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10964     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10965     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10966     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10967     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10968     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10969
10970     /* sent message */
10971     flush_sequence();
10972     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10973     ok_sequence( WmEmptySeq, "no messages", FALSE );
10974     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10975     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10976     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10977
10978     /* sent message with timeout */
10979     flush_sequence();
10980     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10981     ok_sequence( WmEmptySeq, "no messages", FALSE );
10982     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10983     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10984     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10985
10986     /* sent message with timeout and callback */
10987     flush_sequence();
10988     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10989     ok_sequence( WmEmptySeq, "no messages", FALSE );
10990     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10991     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10992     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10993
10994     /* sent message with callback */
10995     flush_sequence();
10996     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10997     ok_sequence( WmEmptySeq, "no messages", FALSE );
10998     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10999     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11000     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11001
11002     /* direct window proc call */
11003     flush_sequence();
11004     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11005     ok_sequence( WmEmptySeq, "no messages", FALSE );
11006     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11007     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11008
11009     /* dispatch message */
11010     msg.hwnd = hwnd;
11011     msg.message = WM_CHAR;
11012     msg.wParam = dbch[0];
11013     msg.lParam = 0;
11014     DispatchMessageA( &msg );
11015     ok_sequence( WmEmptySeq, "no messages", FALSE );
11016     msg.wParam = dbch[1];
11017     DispatchMessageA( &msg );
11018     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11019
11020     /* window handle is irrelevant */
11021     flush_sequence();
11022     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11023     ok_sequence( WmEmptySeq, "no messages", FALSE );
11024     SendMessageA( hwnd, WM_CHAR, dbch[1], 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     /* interleaved post and send */
11029     flush_sequence();
11030     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11031     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11032     ok_sequence( WmEmptySeq, "no messages", FALSE );
11033     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11034     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11035     ok_sequence( WmEmptySeq, "no messages", FALSE );
11036     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11037     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11038     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11039     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11040     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11041     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11042     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11043
11044     /* interleaved sent message and winproc */
11045     flush_sequence();
11046     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11047     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11048     ok_sequence( WmEmptySeq, "no messages", FALSE );
11049     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11050     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11051     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11052     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11053
11054     /* interleaved winproc and dispatch */
11055     msg.hwnd = hwnd;
11056     msg.message = WM_CHAR;
11057     msg.wParam = dbch[0];
11058     msg.lParam = 0;
11059     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11060     DispatchMessageA( &msg );
11061     ok_sequence( WmEmptySeq, "no messages", FALSE );
11062     msg.wParam = dbch[1];
11063     DispatchMessageA( &msg );
11064     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11065     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11066     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11067
11068     /* interleaved sends */
11069     flush_sequence();
11070     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11071     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11072     ok_sequence( WmEmptySeq, "no messages", FALSE );
11073     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11074     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11075     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11076     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11077
11078     /* dbcs WM_CHAR */
11079     flush_sequence();
11080     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11081     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11082     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11083
11084     /* other char messages are not magic */
11085     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11086     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11087     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11088     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11089     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11090     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11091     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11092     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11093     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11094     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11095
11096     /* test retrieving messages */
11097
11098     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11099     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11100     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11101     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11102     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11103     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11104     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11105     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11106     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11107     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11108
11109     /* message filters */
11110     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11111     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11112     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11113     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11114     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11115     /* message id is filtered, hwnd is not */
11116     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
11117     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
11118     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11119     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11120     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11121     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11122
11123     /* mixing GetMessage and PostMessage */
11124     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11125     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
11126     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11127     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11128     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11129     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11130     time = msg.time;
11131     pt = msg.pt;
11132     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11133     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11134     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11135     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11136     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11137     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11138     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11139     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 );
11140     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11141
11142     /* without PM_REMOVE */
11143     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11144     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11145     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11146     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11147     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11148     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11149     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11150     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11151     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11152     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11153     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11154     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11155     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11156     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11157     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11158     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11159     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11160     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11161
11162     DestroyWindow(hwnd);
11163 }
11164
11165 #define ID_LISTBOX 0x000f
11166
11167 static const struct message wm_lb_setcursel_0[] =
11168 {
11169     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11170     { WM_CTLCOLORLISTBOX, sent|parent },
11171     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11172     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11173     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11174     { 0 }
11175 };
11176 static const struct message wm_lb_setcursel_1[] =
11177 {
11178     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11179     { WM_CTLCOLORLISTBOX, sent|parent },
11180     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11181     { WM_CTLCOLORLISTBOX, sent|parent },
11182     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11183     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11184     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11185     { 0 }
11186 };
11187 static const struct message wm_lb_setcursel_2[] =
11188 {
11189     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11190     { WM_CTLCOLORLISTBOX, sent|parent },
11191     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11192     { WM_CTLCOLORLISTBOX, sent|parent },
11193     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11194     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11195     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11196     { 0 }
11197 };
11198 static const struct message wm_lb_click_0[] =
11199 {
11200     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11201     { HCBT_SETFOCUS, hook },
11202     { WM_KILLFOCUS, sent|parent },
11203     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11204     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11205     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11206     { WM_SETFOCUS, sent|defwinproc },
11207
11208     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11209     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11210     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11211     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11212     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11213
11214     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11215     { WM_CTLCOLORLISTBOX, sent|parent },
11216     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11217     { WM_CTLCOLORLISTBOX, sent|parent },
11218     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11219     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11220
11221     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11222     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11223
11224     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11225     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11226     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11227     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11228     { 0 }
11229 };
11230 static const struct message wm_lb_deletestring[] =
11231 {
11232     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11233     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11234     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11235     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11236     { 0 }
11237 };
11238 static const struct message wm_lb_deletestring_reset[] =
11239 {
11240     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11241     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11242     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11243     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11244     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11245     { 0 }
11246 };
11247
11248 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11249
11250 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11251
11252 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11253 {
11254     static LONG defwndproc_counter = 0;
11255     LRESULT ret;
11256     struct recvd_message msg;
11257
11258     /* do not log painting messages */
11259     if (message != WM_PAINT &&
11260         message != WM_NCPAINT &&
11261         message != WM_SYNCPAINT &&
11262         message != WM_ERASEBKGND &&
11263         message != WM_NCHITTEST &&
11264         message != WM_GETTEXT &&
11265         !ignore_message( message ))
11266     {
11267         msg.hwnd = hwnd;
11268         msg.message = message;
11269         msg.flags = sent|wparam|lparam;
11270         if (defwndproc_counter) msg.flags |= defwinproc;
11271         msg.wParam = wp;
11272         msg.lParam = lp;
11273         msg.descr = "listbox";
11274         add_message(&msg);
11275     }
11276
11277     defwndproc_counter++;
11278     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11279     defwndproc_counter--;
11280
11281     return ret;
11282 }
11283
11284 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11285                                int caret_index, int top_index, int line)
11286 {
11287     LRESULT ret;
11288
11289     /* calling an orig proc helps to avoid unnecessary message logging */
11290     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11291     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11292     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11293     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11294     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11295     ok_(__FILE__, line)(ret == caret_index ||
11296                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11297                         "expected caret index %d, got %ld\n", caret_index, ret);
11298     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11299     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11300 }
11301
11302 static void test_listbox_messages(void)
11303 {
11304     HWND parent, listbox;
11305     LRESULT ret;
11306
11307     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11308                              100, 100, 200, 200, 0, 0, 0, NULL);
11309     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11310                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11311                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11312     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11313
11314     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11315
11316     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11317     ok(ret == 0, "expected 0, got %ld\n", ret);
11318     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11319     ok(ret == 1, "expected 1, got %ld\n", ret);
11320     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11321     ok(ret == 2, "expected 2, got %ld\n", ret);
11322
11323     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11324
11325     flush_sequence();
11326
11327     log_all_parent_messages++;
11328
11329     trace("selecting item 0\n");
11330     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11331     ok(ret == 0, "expected 0, got %ld\n", ret);
11332     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11333     check_lb_state(listbox, 3, 0, 0, 0);
11334     flush_sequence();
11335
11336     trace("selecting item 1\n");
11337     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11338     ok(ret == 1, "expected 1, got %ld\n", ret);
11339     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11340     check_lb_state(listbox, 3, 1, 1, 0);
11341
11342     trace("selecting item 2\n");
11343     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11344     ok(ret == 2, "expected 2, got %ld\n", ret);
11345     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11346     check_lb_state(listbox, 3, 2, 2, 0);
11347
11348     trace("clicking on item 0\n");
11349     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11350     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11351     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11352     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11353     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11354     check_lb_state(listbox, 3, 0, 0, 0);
11355     flush_sequence();
11356
11357     trace("deleting item 0\n");
11358     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11359     ok(ret == 2, "expected 2, got %ld\n", ret);
11360     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11361     check_lb_state(listbox, 2, -1, 0, 0);
11362     flush_sequence();
11363
11364     trace("deleting item 0\n");
11365     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11366     ok(ret == 1, "expected 1, got %ld\n", ret);
11367     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11368     check_lb_state(listbox, 1, -1, 0, 0);
11369     flush_sequence();
11370
11371     trace("deleting item 0\n");
11372     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11373     ok(ret == 0, "expected 0, got %ld\n", ret);
11374     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11375     check_lb_state(listbox, 0, -1, 0, 0);
11376     flush_sequence();
11377
11378     trace("deleting item 0\n");
11379     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11380     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11381     check_lb_state(listbox, 0, -1, 0, 0);
11382     flush_sequence();
11383
11384     log_all_parent_messages--;
11385
11386     DestroyWindow(listbox);
11387     DestroyWindow(parent);
11388 }
11389
11390 /*************************** Menu test ******************************/
11391 static const struct message wm_popup_menu_1[] =
11392 {
11393     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11394     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11395     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11396     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11397     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11398     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11399     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11400     { WM_INITMENU, sent|lparam, 0, 0 },
11401     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11402     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11403     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11404     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11405     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11406     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11407     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11408     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11409     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11410     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11411     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11412     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11413     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11414     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11415     { 0 }
11416 };
11417 static const struct message wm_popup_menu_2[] =
11418 {
11419     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11420     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11421     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11422     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11423     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11424     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11425     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11426     { WM_INITMENU, sent|lparam, 0, 0 },
11427     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11428     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11429     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11430     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11431     { HCBT_CREATEWND, hook },
11432     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11433                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11434     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11435     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11436     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11437     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11438     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11439     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11440     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11441     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11442     { HCBT_DESTROYWND, hook },
11443     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11444     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11445     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11446     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11447     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11448     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11449     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11450     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11451     { 0 }
11452 };
11453 static const struct message wm_popup_menu_3[] =
11454 {
11455     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11456     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11457     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11458     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11459     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11460     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11461     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11462     { WM_INITMENU, sent|lparam, 0, 0 },
11463     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11464     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11465     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11466     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11467     { HCBT_CREATEWND, hook },
11468     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11469                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11470     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11471     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11472     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11473     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11474     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11475     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11476     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11477     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11478     { HCBT_DESTROYWND, hook },
11479     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11480     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11481     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11482     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11483     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11484     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11485     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11486     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11487     { 0 }
11488 };
11489
11490 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11491 {
11492     if (message == WM_ENTERIDLE ||
11493         message == WM_INITMENU ||
11494         message == WM_INITMENUPOPUP ||
11495         message == WM_MENUSELECT ||
11496         message == WM_PARENTNOTIFY ||
11497         message == WM_ENTERMENULOOP ||
11498         message == WM_EXITMENULOOP ||
11499         message == WM_UNINITMENUPOPUP ||
11500         message == WM_KEYDOWN ||
11501         message == WM_KEYUP ||
11502         message == WM_CHAR ||
11503         message == WM_SYSKEYDOWN ||
11504         message == WM_SYSKEYUP ||
11505         message == WM_SYSCHAR ||
11506         message == WM_COMMAND ||
11507         message == WM_MENUCOMMAND)
11508     {
11509         struct recvd_message msg;
11510
11511         msg.hwnd = hwnd;
11512         msg.message = message;
11513         msg.flags = sent|wparam|lparam;
11514         msg.wParam = wp;
11515         msg.lParam = lp;
11516         msg.descr = "parent_menu_proc";
11517         add_message(&msg);
11518     }
11519
11520     return DefWindowProcA(hwnd, message, wp, lp);
11521 }
11522
11523 static void set_menu_style(HMENU hmenu, DWORD style)
11524 {
11525     MENUINFO mi;
11526     BOOL ret;
11527
11528     mi.cbSize = sizeof(mi);
11529     mi.fMask = MIM_STYLE;
11530     mi.dwStyle = style;
11531     SetLastError(0xdeadbeef);
11532     ret = pSetMenuInfo(hmenu, &mi);
11533     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11534 }
11535
11536 static DWORD get_menu_style(HMENU hmenu)
11537 {
11538     MENUINFO mi;
11539     BOOL ret;
11540
11541     mi.cbSize = sizeof(mi);
11542     mi.fMask = MIM_STYLE;
11543     mi.dwStyle = 0;
11544     SetLastError(0xdeadbeef);
11545     ret = pGetMenuInfo(hmenu, &mi);
11546     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11547
11548     return mi.dwStyle;
11549 }
11550
11551 static void test_menu_messages(void)
11552 {
11553     MSG msg;
11554     WNDCLASSA cls;
11555     HMENU hmenu, hmenu_popup;
11556     HWND hwnd;
11557     DWORD style;
11558
11559     if (!pGetMenuInfo || !pSetMenuInfo)
11560     {
11561         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11562         return;
11563     }
11564     cls.style = 0;
11565     cls.lpfnWndProc = parent_menu_proc;
11566     cls.cbClsExtra = 0;
11567     cls.cbWndExtra = 0;
11568     cls.hInstance = GetModuleHandleA(0);
11569     cls.hIcon = 0;
11570     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11571     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11572     cls.lpszMenuName = NULL;
11573     cls.lpszClassName = "TestMenuClass";
11574     UnregisterClass(cls.lpszClassName, cls.hInstance);
11575     if (!RegisterClassA(&cls)) assert(0);
11576
11577     SetLastError(0xdeadbeef);
11578     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11579                            100, 100, 200, 200, 0, 0, 0, NULL);
11580     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11581
11582     SetLastError(0xdeadbeef);
11583     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11584     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11585
11586     SetMenu(hwnd, hmenu);
11587     SetForegroundWindow( hwnd );
11588
11589     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11590     style = get_menu_style(hmenu);
11591     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11592
11593     hmenu_popup = GetSubMenu(hmenu, 0);
11594     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11595     style = get_menu_style(hmenu_popup);
11596     ok(style == 0, "expected 0, got %u\n", style);
11597
11598     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11599     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11600     style = get_menu_style(hmenu_popup);
11601     ok(style == 0, "expected 0, got %u\n", style);
11602
11603     /* Alt+E, Enter */
11604     trace("testing a popup menu command\n");
11605     flush_sequence();
11606     keybd_event(VK_MENU, 0, 0, 0);
11607     keybd_event('E', 0, 0, 0);
11608     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11609     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11610     keybd_event(VK_RETURN, 0, 0, 0);
11611     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11612     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11613     {
11614         TranslateMessage(&msg);
11615         DispatchMessage(&msg);
11616     }
11617     if (!sequence_cnt)  /* we didn't get any message */
11618     {
11619         skip( "queuing key events not supported\n" );
11620         goto done;
11621     }
11622     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
11623     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
11624     {
11625         win_skip( "menu tracking through VK_MENU not supported\n" );
11626         goto done;
11627     }
11628     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11629
11630     /* Alt+F, Right, Enter */
11631     trace("testing submenu of a popup menu command\n");
11632     flush_sequence();
11633     keybd_event(VK_MENU, 0, 0, 0);
11634     keybd_event('F', 0, 0, 0);
11635     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11636     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11637     keybd_event(VK_RIGHT, 0, 0, 0);
11638     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11639     keybd_event(VK_RETURN, 0, 0, 0);
11640     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11641     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11642     {
11643         TranslateMessage(&msg);
11644         DispatchMessage(&msg);
11645     }
11646     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11647
11648     set_menu_style(hmenu, 0);
11649     style = get_menu_style(hmenu);
11650     ok(style == 0, "expected 0, got %u\n", style);
11651
11652     hmenu_popup = GetSubMenu(hmenu, 0);
11653     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11654     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11655     style = get_menu_style(hmenu_popup);
11656     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11657
11658     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11659     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11660     style = get_menu_style(hmenu_popup);
11661     ok(style == 0, "expected 0, got %u\n", style);
11662
11663     /* Alt+F, Right, Enter */
11664     trace("testing submenu of a popup menu command\n");
11665     flush_sequence();
11666     keybd_event(VK_MENU, 0, 0, 0);
11667     keybd_event('F', 0, 0, 0);
11668     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11669     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11670     keybd_event(VK_RIGHT, 0, 0, 0);
11671     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11672     keybd_event(VK_RETURN, 0, 0, 0);
11673     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11674     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11675     {
11676         TranslateMessage(&msg);
11677         DispatchMessage(&msg);
11678     }
11679     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11680
11681 done:
11682     DestroyWindow(hwnd);
11683     DestroyMenu(hmenu);
11684 }
11685
11686
11687 static void test_paintingloop(void)
11688 {
11689     HWND hwnd;
11690
11691     paint_loop_done = 0;
11692     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11693                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11694                                 100, 100, 100, 100, 0, 0, 0, NULL );
11695     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11696     ShowWindow(hwnd,SW_NORMAL);
11697     SetFocus(hwnd);
11698
11699     while (!paint_loop_done)
11700     {
11701         MSG msg;
11702         if (PeekMessageA(&msg, 0, 0, 0, 1))
11703         {
11704             TranslateMessage(&msg);
11705             DispatchMessage(&msg);
11706         }
11707     }
11708     DestroyWindow(hwnd);
11709 }
11710
11711 static void test_defwinproc(void)
11712 {
11713     HWND hwnd;
11714     MSG msg;
11715     int gotwmquit = FALSE;
11716     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
11717     assert(hwnd);
11718     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
11719     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
11720         if( msg.message == WM_QUIT) gotwmquit = TRUE;
11721         DispatchMessageA( &msg );
11722     }
11723     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
11724     DestroyWindow( hwnd);
11725 }
11726
11727 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
11728 static void clear_clipboard_(int line, HWND hWnd)
11729 {
11730     BOOL succ;
11731     succ = OpenClipboard(hWnd);
11732     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
11733     succ = EmptyClipboard();
11734     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
11735     succ = CloseClipboard();
11736     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
11737 }
11738
11739 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
11740 static void expect_HWND_(int line, HWND expected, HWND got)
11741 {
11742     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
11743 }
11744
11745 static WNDPROC pOldViewerProc;
11746
11747 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
11748 {
11749     static BOOL recursion_guard;
11750
11751     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
11752     {
11753         recursion_guard = TRUE;
11754         clear_clipboard(hWnd);
11755         recursion_guard = FALSE;
11756     }
11757     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
11758 }
11759
11760 static void test_clipboard_viewers(void)
11761 {
11762     static struct message wm_change_cb_chain[] =
11763     {
11764         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
11765         { 0 }
11766     };
11767     static const struct message wm_clipboard_destroyed[] =
11768     {
11769         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
11770         { 0 }
11771     };
11772     static struct message wm_clipboard_changed[] =
11773     {
11774         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
11775         { 0 }
11776     };
11777     static struct message wm_clipboard_changed_and_owned[] =
11778     {
11779         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
11780         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
11781         { 0 }
11782     };
11783
11784     HINSTANCE hInst = GetModuleHandleA(NULL);
11785     HWND hWnd1, hWnd2, hWnd3;
11786     HWND hOrigViewer;
11787     HWND hRet;
11788
11789     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
11790         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
11791         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11792         GetDesktopWindow(), NULL, hInst, NULL);
11793     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
11794         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
11795         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11796         GetDesktopWindow(), NULL, hInst, NULL);
11797     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
11798         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
11799         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11800         GetDesktopWindow(), NULL, hInst, NULL);
11801     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
11802     assert(hWnd1 && hWnd2 && hWnd3);
11803
11804     flush_sequence();
11805
11806     /* Test getting the clipboard viewer and setting the viewer to NULL. */
11807     hOrigViewer = GetClipboardViewer();
11808     hRet = SetClipboardViewer(NULL);
11809     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
11810     expect_HWND(hOrigViewer, hRet);
11811     expect_HWND(NULL, GetClipboardViewer());
11812
11813     /* Test registering hWnd1 as a viewer. */
11814     hRet = SetClipboardViewer(hWnd1);
11815     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
11816     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", TRUE);
11817     expect_HWND(NULL, hRet);
11818     expect_HWND(hWnd1, GetClipboardViewer());
11819
11820     /* Test that changing the clipboard actually refreshes the registered viewer. */
11821     clear_clipboard(hWnd1);
11822     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
11823     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", TRUE);
11824
11825     /* Again, but with different owner. */
11826     clear_clipboard(hWnd2);
11827     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
11828     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", TRUE);
11829
11830     /* Test re-registering same window. */
11831     hRet = SetClipboardViewer(hWnd1);
11832     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
11833     ok_sequence(wm_clipboard_changed, "set viewer 1->1", TRUE);
11834     expect_HWND(hWnd1, hRet);
11835     expect_HWND(hWnd1, GetClipboardViewer());
11836
11837     /* Test ChangeClipboardChain. */
11838     ChangeClipboardChain(hWnd2, hWnd3);
11839     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
11840     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
11841     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
11842     expect_HWND(hWnd1, GetClipboardViewer());
11843
11844     ChangeClipboardChain(hWnd2, NULL);
11845     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
11846     wm_change_cb_chain[0].lParam = 0;
11847     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
11848     expect_HWND(hWnd1, GetClipboardViewer());
11849
11850     ChangeClipboardChain(NULL, hWnd2);
11851     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
11852     expect_HWND(hWnd1, GetClipboardViewer());
11853
11854     /* Actually change clipboard viewer with ChangeClipboardChain. */
11855     ChangeClipboardChain(hWnd1, hWnd2);
11856     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
11857     expect_HWND(hWnd2, GetClipboardViewer());
11858
11859     /* Test that no refresh messages are sent when viewer has unregistered. */
11860     clear_clipboard(hWnd2);
11861     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
11862
11863     /* Register hWnd1 again. */
11864     ChangeClipboardChain(hWnd2, hWnd1);
11865     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
11866     expect_HWND(hWnd1, GetClipboardViewer());
11867
11868     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
11869      * changes the clipboard. When this happens, the system shouldn't send
11870      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
11871      */
11872     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
11873     clear_clipboard(hWnd2);
11874     /* The clipboard owner is changed in recursive_viewer_proc: */
11875     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
11876     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
11877
11878     /* Test unregistering. */
11879     ChangeClipboardChain(hWnd1, NULL);
11880     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
11881     expect_HWND(NULL, GetClipboardViewer());
11882
11883     clear_clipboard(hWnd1);
11884     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
11885
11886     DestroyWindow(hWnd1);
11887     DestroyWindow(hWnd2);
11888     DestroyWindow(hWnd3);
11889     SetClipboardViewer(hOrigViewer);
11890 }
11891
11892 static void test_PostMessage(void)
11893 {
11894     static const struct
11895     {
11896         HWND hwnd;
11897         BOOL ret;
11898     } data[] =
11899     {
11900         { HWND_TOP /* 0 */, TRUE },
11901         { HWND_BROADCAST, TRUE },
11902         { HWND_BOTTOM, TRUE },
11903         { HWND_TOPMOST, TRUE },
11904         { HWND_NOTOPMOST, FALSE },
11905         { HWND_MESSAGE, FALSE },
11906         { (HWND)0xdeadbeef, FALSE }
11907     };
11908     int i;
11909     HWND hwnd;
11910     BOOL ret;
11911     MSG msg;
11912     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
11913
11914     SetLastError(0xdeadbeef);
11915     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11916     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
11917     {
11918         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
11919         return;
11920     }
11921     assert(hwnd);
11922
11923     flush_events();
11924
11925     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
11926     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
11927
11928     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
11929     {
11930         memset(&msg, 0xab, sizeof(msg));
11931         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
11932         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
11933         if (data[i].ret)
11934         {
11935             if (data[i].hwnd)
11936                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
11937                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
11938                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
11939                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
11940             else
11941                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
11942                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
11943                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
11944                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
11945         }
11946     }
11947
11948     DestroyWindow(hwnd);
11949     flush_events();
11950 }
11951
11952 START_TEST(msg)
11953 {
11954     BOOL ret;
11955     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11956
11957     init_procs();
11958
11959     if (!RegisterWindowClasses()) assert(0);
11960
11961     if (pSetWinEventHook)
11962     {
11963         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11964                                        GetModuleHandleA(0), win_event_proc,
11965                                        0, GetCurrentThreadId(),
11966                                        WINEVENT_INCONTEXT);
11967         if (pIsWinEventHookInstalled && hEvent_hook)
11968         {
11969             UINT event;
11970             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11971                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11972         }
11973     }
11974     if (!hEvent_hook) win_skip( "no win event hook support\n" );
11975
11976     cbt_hook_thread_id = GetCurrentThreadId();
11977     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11978     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
11979
11980     test_winevents();
11981
11982     /* Fix message sequences before removing 4 lines below */
11983 #if 1
11984     if (pUnhookWinEvent && hEvent_hook)
11985     {
11986         ret = pUnhookWinEvent(hEvent_hook);
11987         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11988         pUnhookWinEvent = 0;
11989     }
11990     hEvent_hook = 0;
11991 #endif
11992
11993     test_PostMessage();
11994     test_ShowWindow();
11995     test_PeekMessage();
11996     test_PeekMessage2();
11997     test_scrollwindowex();
11998     test_messages();
11999     test_setwindowpos();
12000     test_showwindow();
12001     invisible_parent_tests();
12002     test_mdi_messages();
12003     test_button_messages();
12004     test_static_messages();
12005     test_listbox_messages();
12006     test_combobox_messages();
12007     test_wmime_keydown_message();
12008     test_paint_messages();
12009     test_interthread_messages();
12010     test_message_conversion();
12011     test_accelerators();
12012     test_timers();
12013     test_timers_no_wnd();
12014     if (hCBT_hook) test_set_hook();
12015     test_DestroyWindow();
12016     test_DispatchMessage();
12017     test_SendMessageTimeout();
12018     test_edit_messages();
12019     test_quit_message();
12020     test_SetActiveWindow();
12021
12022     if (!pTrackMouseEvent)
12023         win_skip("TrackMouseEvent is not available\n");
12024     else
12025         test_TrackMouseEvent();
12026
12027     test_SetWindowRgn();
12028     test_sys_menu();
12029     test_dialog_messages();
12030     test_nullCallback();
12031     test_dbcs_wm_char();
12032     test_menu_messages();
12033     test_paintingloop();
12034     test_defwinproc();
12035     test_clipboard_viewers();
12036     /* keep it the last test, under Windows it tends to break the tests
12037      * which rely on active/foreground windows being correct.
12038      */
12039     test_SetForegroundWindow();
12040
12041     UnhookWindowsHookEx(hCBT_hook);
12042     if (pUnhookWinEvent && hEvent_hook)
12043     {
12044         ret = pUnhookWinEvent(hEvent_hook);
12045         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
12046         SetLastError(0xdeadbeef);
12047         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
12048         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
12049            GetLastError() == 0xdeadbeef, /* Win9x */
12050            "unexpected error %d\n", GetLastError());
12051     }
12052 }