fltlib: Add a stub dll.
[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 static VOID CALLBACK tfunc_crash(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7817 {
7818     /* Crash on purpose */
7819     *(volatile int *)0 = 2;
7820 }
7821
7822 #define TIMER_ID  0x19
7823
7824 static DWORD WINAPI timer_thread_proc(LPVOID x)
7825 {
7826     struct timer_info *info = x;
7827     DWORD r;
7828
7829     r = KillTimer(info->hWnd, 0x19);
7830     ok(r,"KillTimer failed in thread\n");
7831     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7832     ok(r,"SetTimer failed in thread\n");
7833     ok(r==TIMER_ID,"SetTimer id different\n");
7834     r = SetEvent(info->handles[0]);
7835     ok(r,"SetEvent failed in thread\n");
7836     return 0;
7837 }
7838
7839 static void test_timers(void)
7840 {
7841     struct timer_info info;
7842     DWORD id;
7843     MSG msg;
7844
7845     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7846        WS_OVERLAPPEDWINDOW ,
7847        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7848        NULL, NULL, 0);
7849
7850     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7851     ok(info.id, "SetTimer failed\n");
7852     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7853     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7854     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7855
7856     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7857
7858     WaitForSingleObject(info.handles[1], INFINITE);
7859
7860     CloseHandle(info.handles[0]);
7861     CloseHandle(info.handles[1]);
7862
7863     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7864
7865     /* Test timer callback with crash */
7866     info.id = SetTimer(info.hWnd, TIMER_ID, 0, tfunc_crash);
7867     ok(info.id, "SetTimer failed\n");
7868     Sleep(150);
7869     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7870
7871     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7872 }
7873
7874 static int count = 0;
7875 static VOID CALLBACK callback_count(
7876     HWND hwnd,
7877     UINT uMsg,
7878     UINT_PTR idEvent,
7879     DWORD dwTime
7880 )
7881 {
7882     count++;
7883 }
7884
7885 static void test_timers_no_wnd(void)
7886 {
7887     UINT_PTR id, id2;
7888     MSG msg;
7889
7890     count = 0;
7891     id = SetTimer(NULL, 0, 100, callback_count);
7892     ok(id != 0, "did not get id from SetTimer.\n");
7893     id2 = SetTimer(NULL, id, 200, callback_count);
7894     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7895     Sleep(150);
7896     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7897     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7898     Sleep(150);
7899     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7900     ok(count == 1, "did not get one count as expected (%i).\n", count);
7901     KillTimer(NULL, id);
7902     Sleep(250);
7903     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7904     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7905 }
7906
7907 /* Various win events with arbitrary parameters */
7908 static const struct message WmWinEventsSeq[] = {
7909     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7910     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7911     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7912     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7913     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7914     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7915     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7916     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7917     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7918     /* our win event hook ignores OBJID_CURSOR events */
7919     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7920     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7921     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7922     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7923     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7924     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7925     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7926     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7927     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7928     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7929     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7930     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7931     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7932     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7933     { 0 }
7934 };
7935 static const struct message WmWinEventCaretSeq[] = {
7936     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7937     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7938     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7939     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7940     { 0 }
7941 };
7942 static const struct message WmWinEventCaretSeq_2[] = {
7943     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7944     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7945     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7946     { 0 }
7947 };
7948 static const struct message WmWinEventAlertSeq[] = {
7949     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7950     { 0 }
7951 };
7952 static const struct message WmWinEventAlertSeq_2[] = {
7953     /* create window in the thread proc */
7954     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7955     /* our test event */
7956     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7957     { 0 }
7958 };
7959 static const struct message WmGlobalHookSeq_1[] = {
7960     /* create window in the thread proc */
7961     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7962     /* our test events */
7963     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7964     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7965     { 0 }
7966 };
7967 static const struct message WmGlobalHookSeq_2[] = {
7968     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7969     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7970     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7971     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7972     { 0 }
7973 };
7974
7975 static const struct message WmMouseLLHookSeq[] = {
7976     { WM_MOUSEMOVE, hook },
7977     { WM_LBUTTONUP, hook },
7978     { WM_MOUSEMOVE, hook },
7979     { 0 }
7980 };
7981
7982 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7983                                          DWORD event,
7984                                          HWND hwnd,
7985                                          LONG object_id,
7986                                          LONG child_id,
7987                                          DWORD thread_id,
7988                                          DWORD event_time)
7989 {
7990     char buf[256];
7991
7992     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7993     {
7994         if (!lstrcmpiA(buf, "TestWindowClass") ||
7995             !lstrcmpiA(buf, "static"))
7996         {
7997             struct recvd_message msg;
7998
7999             msg.hwnd = hwnd;
8000             msg.message = event;
8001             msg.flags = winevent_hook|wparam|lparam;
8002             msg.wParam = object_id;
8003             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8004             msg.descr = "WEH_2";
8005             add_message(&msg);
8006         }
8007     }
8008 }
8009
8010 static HHOOK hCBT_global_hook;
8011 static DWORD cbt_global_hook_thread_id;
8012
8013 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
8014
8015     HWND hwnd;
8016     char buf[256];
8017
8018     if (nCode == HCBT_SYSCOMMAND)
8019     {
8020         struct recvd_message msg;
8021
8022         msg.hwnd = 0;
8023         msg.message = nCode;
8024         msg.flags = hook|wparam|lparam;
8025         msg.wParam = wParam;
8026         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8027         msg.descr = "CBT_2";
8028         add_message(&msg);
8029
8030         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8031     }
8032     /* WH_MOUSE_LL hook */
8033     if (nCode == HC_ACTION)
8034     {
8035         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8036
8037         /* we can't test for real mouse events */
8038         if (mhll->flags & LLMHF_INJECTED)
8039         {
8040             struct recvd_message msg;
8041
8042             memset (&msg, 0, sizeof (msg));
8043             msg.message = wParam;
8044             msg.flags = hook;
8045             msg.descr = "CBT_2";
8046             add_message(&msg);
8047         }
8048         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8049     }
8050
8051     /* Log also SetFocus(0) calls */
8052     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8053
8054     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8055     {
8056         if (!lstrcmpiA(buf, "TestWindowClass") ||
8057             !lstrcmpiA(buf, "static"))
8058         {
8059             struct recvd_message msg;
8060
8061             msg.hwnd = hwnd;
8062             msg.message = nCode;
8063             msg.flags = hook|wparam|lparam;
8064             msg.wParam = wParam;
8065             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8066             msg.descr = "CBT_2";
8067             add_message(&msg);
8068         }
8069     }
8070     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8071 }
8072
8073 static DWORD WINAPI win_event_global_thread_proc(void *param)
8074 {
8075     HWND hwnd;
8076     MSG msg;
8077     HANDLE hevent = *(HANDLE *)param;
8078
8079     assert(pNotifyWinEvent);
8080
8081     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8082     assert(hwnd);
8083     trace("created thread window %p\n", hwnd);
8084
8085     *(HWND *)param = hwnd;
8086
8087     flush_sequence();
8088     /* this event should be received only by our new hook proc,
8089      * an old one does not expect an event from another thread.
8090      */
8091     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8092     SetEvent(hevent);
8093
8094     while (GetMessage(&msg, 0, 0, 0))
8095     {
8096         TranslateMessage(&msg);
8097         DispatchMessage(&msg);
8098     }
8099     return 0;
8100 }
8101
8102 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8103 {
8104     HWND hwnd;
8105     MSG msg;
8106     HANDLE hevent = *(HANDLE *)param;
8107
8108     flush_sequence();
8109     /* these events should be received only by our new hook proc,
8110      * an old one does not expect an event from another thread.
8111      */
8112
8113     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8114     assert(hwnd);
8115     trace("created thread window %p\n", hwnd);
8116
8117     *(HWND *)param = hwnd;
8118
8119     /* Windows doesn't like when a thread plays games with the focus,
8120        that leads to all kinds of misbehaviours and failures to activate
8121        a window. So, better keep next lines commented out.
8122     SetFocus(0);
8123     SetFocus(hwnd);*/
8124
8125     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8126     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8127
8128     SetEvent(hevent);
8129
8130     while (GetMessage(&msg, 0, 0, 0))
8131     {
8132         TranslateMessage(&msg);
8133         DispatchMessage(&msg);
8134     }
8135     return 0;
8136 }
8137
8138 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8139 {
8140     HWND hwnd;
8141     MSG msg;
8142     HANDLE hevent = *(HANDLE *)param;
8143
8144     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8145     assert(hwnd);
8146     trace("created thread window %p\n", hwnd);
8147
8148     *(HWND *)param = hwnd;
8149
8150     flush_sequence();
8151
8152     /* Windows doesn't like when a thread plays games with the focus,
8153      * that leads to all kinds of misbehaviours and failures to activate
8154      * a window. So, better don't generate a mouse click message below.
8155      */
8156     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8157     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8158     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8159
8160     SetEvent(hevent);
8161     while (GetMessage(&msg, 0, 0, 0))
8162     {
8163         TranslateMessage(&msg);
8164         DispatchMessage(&msg);
8165     }
8166     return 0;
8167 }
8168
8169 static void test_winevents(void)
8170 {
8171     BOOL ret;
8172     MSG msg;
8173     HWND hwnd, hwnd2;
8174     UINT i;
8175     HANDLE hthread, hevent;
8176     DWORD tid;
8177     HWINEVENTHOOK hhook;
8178     const struct message *events = WmWinEventsSeq;
8179
8180     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8181                            WS_OVERLAPPEDWINDOW,
8182                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8183                            NULL, NULL, 0);
8184     assert(hwnd);
8185
8186     /****** start of global hook test *************/
8187     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8188     if (!hCBT_global_hook)
8189     {
8190         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8191         skip( "cannot set global hook\n" );
8192         return;
8193     }
8194
8195     hevent = CreateEventA(NULL, 0, 0, NULL);
8196     assert(hevent);
8197     hwnd2 = hevent;
8198
8199     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8200     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8201
8202     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8203
8204     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8205
8206     flush_sequence();
8207     /* this one should be received only by old hook proc */
8208     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8209     /* this one should be received only by old hook proc */
8210     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8211
8212     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8213
8214     ret = UnhookWindowsHookEx(hCBT_global_hook);
8215     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8216
8217     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8218     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8219     CloseHandle(hthread);
8220     CloseHandle(hevent);
8221     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8222     /****** end of global hook test *************/
8223
8224     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8225     {
8226         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8227         return;
8228     }
8229
8230     flush_sequence();
8231
8232     if (0)
8233     {
8234     /* this test doesn't pass under Win9x */
8235     /* win2k ignores events with hwnd == 0 */
8236     SetLastError(0xdeadbeef);
8237     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8238     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8239        GetLastError() == 0xdeadbeef, /* Win9x */
8240        "unexpected error %d\n", GetLastError());
8241     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8242     }
8243
8244     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8245         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8246
8247     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8248
8249     /****** start of event filtering test *************/
8250     hhook = pSetWinEventHook(
8251         EVENT_OBJECT_SHOW, /* 0x8002 */
8252         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8253         GetModuleHandleA(0), win_event_global_hook_proc,
8254         GetCurrentProcessId(), 0,
8255         WINEVENT_INCONTEXT);
8256     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8257
8258     hevent = CreateEventA(NULL, 0, 0, NULL);
8259     assert(hevent);
8260     hwnd2 = hevent;
8261
8262     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8263     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8264
8265     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8266
8267     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8268
8269     flush_sequence();
8270     /* this one should be received only by old hook proc */
8271     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8272     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8273     /* this one should be received only by old hook proc */
8274     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8275
8276     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8277
8278     ret = pUnhookWinEvent(hhook);
8279     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8280
8281     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8282     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8283     CloseHandle(hthread);
8284     CloseHandle(hevent);
8285     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8286     /****** end of event filtering test *************/
8287
8288     /****** start of out of context event test *************/
8289     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8290         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8291         WINEVENT_OUTOFCONTEXT);
8292     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8293
8294     hevent = CreateEventA(NULL, 0, 0, NULL);
8295     assert(hevent);
8296     hwnd2 = hevent;
8297
8298     flush_sequence();
8299
8300     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8301     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8302
8303     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8304
8305     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8306     /* process pending winevent messages */
8307     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8308     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8309
8310     flush_sequence();
8311     /* this one should be received only by old hook proc */
8312     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8313     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8314     /* this one should be received only by old hook proc */
8315     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8316
8317     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8318     /* process pending winevent messages */
8319     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8320     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8321
8322     ret = pUnhookWinEvent(hhook);
8323     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8324
8325     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8326     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8327     CloseHandle(hthread);
8328     CloseHandle(hevent);
8329     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8330     /****** end of out of context event test *************/
8331
8332     /****** start of MOUSE_LL hook test *************/
8333     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8334     /* WH_MOUSE_LL is not supported on Win9x platforms */
8335     if (!hCBT_global_hook)
8336     {
8337         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8338         goto skip_mouse_ll_hook_test;
8339     }
8340
8341     hevent = CreateEventA(NULL, 0, 0, NULL);
8342     assert(hevent);
8343     hwnd2 = hevent;
8344
8345     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8346     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8347
8348     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8349         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8350
8351     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8352     flush_sequence();
8353
8354     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8355     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8356     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8357
8358     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8359
8360     ret = UnhookWindowsHookEx(hCBT_global_hook);
8361     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8362
8363     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8364     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8365     CloseHandle(hthread);
8366     CloseHandle(hevent);
8367     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8368     /****** end of MOUSE_LL hook test *************/
8369 skip_mouse_ll_hook_test:
8370
8371     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8372 }
8373
8374 static void test_set_hook(void)
8375 {
8376     BOOL ret;
8377     HHOOK hhook;
8378     HWINEVENTHOOK hwinevent_hook;
8379
8380     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8381     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8382     UnhookWindowsHookEx(hhook);
8383
8384     if (0)
8385     {
8386     /* this test doesn't pass under Win9x: BUG! */
8387     SetLastError(0xdeadbeef);
8388     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8389     ok(!hhook, "global hook requires hModule != 0\n");
8390     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8391     }
8392
8393     SetLastError(0xdeadbeef);
8394     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8395     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8396     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8397        GetLastError() == 0xdeadbeef, /* Win9x */
8398        "unexpected error %d\n", GetLastError());
8399
8400     SetLastError(0xdeadbeef);
8401     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8402     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8403        GetLastError() == 0xdeadbeef, /* Win9x */
8404        "unexpected error %d\n", GetLastError());
8405
8406     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8407
8408     /* even process local incontext hooks require hmodule */
8409     SetLastError(0xdeadbeef);
8410     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8411         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8412     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8413     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8414        GetLastError() == 0xdeadbeef, /* Win9x */
8415        "unexpected error %d\n", GetLastError());
8416
8417     /* even thread local incontext hooks require hmodule */
8418     SetLastError(0xdeadbeef);
8419     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8420         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8421     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8422     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8423        GetLastError() == 0xdeadbeef, /* Win9x */
8424        "unexpected error %d\n", GetLastError());
8425
8426     if (0)
8427     {
8428     /* these 3 tests don't pass under Win9x */
8429     SetLastError(0xdeadbeef);
8430     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8431         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8432     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8433     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8434
8435     SetLastError(0xdeadbeef);
8436     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8437         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8438     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8439     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8440
8441     SetLastError(0xdeadbeef);
8442     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8443         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8444     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8445     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8446     }
8447
8448     SetLastError(0xdeadbeef);
8449     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8450         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8451     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8452     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8453     ret = pUnhookWinEvent(hwinevent_hook);
8454     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8455
8456 todo_wine {
8457     /* This call succeeds under win2k SP4, but fails under Wine.
8458        Does win2k test/use passed process id? */
8459     SetLastError(0xdeadbeef);
8460     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8461         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8462     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8463     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8464     ret = pUnhookWinEvent(hwinevent_hook);
8465     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8466 }
8467
8468     SetLastError(0xdeadbeef);
8469     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8470     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8471         GetLastError() == 0xdeadbeef, /* Win9x */
8472         "unexpected error %d\n", GetLastError());
8473 }
8474
8475 static const struct message ScrollWindowPaint1[] = {
8476     { WM_PAINT, sent },
8477     { WM_ERASEBKGND, sent|beginpaint },
8478     { WM_GETTEXTLENGTH, sent|optional },
8479     { WM_PAINT, sent|optional },
8480     { WM_NCPAINT, sent|beginpaint|optional },
8481     { WM_GETTEXT, sent|beginpaint|optional },
8482     { WM_GETTEXT, sent|beginpaint|optional },
8483     { WM_GETTEXT, sent|beginpaint|optional },
8484     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8485     { WM_ERASEBKGND, sent|beginpaint|optional },
8486     { 0 }
8487 };
8488
8489 static const struct message ScrollWindowPaint2[] = {
8490     { WM_PAINT, sent },
8491     { 0 }
8492 };
8493
8494 static void test_scrollwindowex(void)
8495 {
8496     HWND hwnd, hchild;
8497     RECT rect={0,0,130,130};
8498
8499     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8500             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8501             100, 100, 200, 200, 0, 0, 0, NULL);
8502     ok (hwnd != 0, "Failed to create overlapped window\n");
8503     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8504             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8505             10, 10, 150, 150, hwnd, 0, 0, NULL);
8506     ok (hchild != 0, "Failed to create child\n");
8507     UpdateWindow(hwnd);
8508     flush_events();
8509     flush_sequence();
8510
8511     /* scroll without the child window */
8512     trace("start scroll\n");
8513     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8514             SW_ERASE|SW_INVALIDATE);
8515     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8516     trace("end scroll\n");
8517     flush_sequence();
8518     flush_events();
8519     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8520     flush_events();
8521     flush_sequence();
8522
8523     /* Now without the SW_ERASE flag */
8524     trace("start scroll\n");
8525     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8526     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8527     trace("end scroll\n");
8528     flush_sequence();
8529     flush_events();
8530     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8531     flush_events();
8532     flush_sequence();
8533
8534     /* now scroll the child window as well */
8535     trace("start scroll\n");
8536     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8537             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8538     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8539     /* windows sometimes a WM_MOVE */
8540     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8541     trace("end scroll\n");
8542     flush_sequence();
8543     flush_events();
8544     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8545     flush_events();
8546     flush_sequence();
8547
8548     /* now scroll with ScrollWindow() */
8549     trace("start scroll with ScrollWindow\n");
8550     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8551     trace("end scroll\n");
8552     flush_sequence();
8553     flush_events();
8554     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8555
8556     ok(DestroyWindow(hchild), "failed to destroy window\n");
8557     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8558     flush_sequence();
8559 }
8560
8561 static const struct message destroy_window_with_children[] = {
8562     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8563     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8564     { 0x0090, sent|optional },
8565     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8566     { 0x0090, sent|optional },
8567     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8568     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8569     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8570     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8571     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8572     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8573     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8574     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8575     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8576     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8577     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8578     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8579     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8580     { 0 }
8581 };
8582
8583 static void test_DestroyWindow(void)
8584 {
8585     BOOL ret;
8586     HWND parent, child1, child2, child3, child4, test;
8587     UINT_PTR child_id = WND_CHILD_ID + 1;
8588
8589     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8590                              100, 100, 200, 200, 0, 0, 0, NULL);
8591     assert(parent != 0);
8592     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8593                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8594     assert(child1 != 0);
8595     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8596                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8597     assert(child2 != 0);
8598     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8599                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8600     assert(child3 != 0);
8601     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8602                              0, 0, 50, 50, parent, 0, 0, NULL);
8603     assert(child4 != 0);
8604
8605     /* test owner/parent of child2 */
8606     test = GetParent(child2);
8607     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8608     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8609     if(pGetAncestor) {
8610         test = pGetAncestor(child2, GA_PARENT);
8611         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8612     }
8613     test = GetWindow(child2, GW_OWNER);
8614     ok(!test, "wrong owner %p\n", test);
8615
8616     test = SetParent(child2, parent);
8617     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8618
8619     /* test owner/parent of the parent */
8620     test = GetParent(parent);
8621     ok(!test, "wrong parent %p\n", test);
8622     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8623     if(pGetAncestor) {
8624         test = pGetAncestor(parent, GA_PARENT);
8625         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8626     }
8627     test = GetWindow(parent, GW_OWNER);
8628     ok(!test, "wrong owner %p\n", test);
8629
8630     /* test owner/parent of child1 */
8631     test = GetParent(child1);
8632     ok(test == parent, "wrong parent %p\n", test);
8633     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8634     if(pGetAncestor) {
8635         test = pGetAncestor(child1, GA_PARENT);
8636         ok(test == parent, "wrong parent %p\n", test);
8637     }
8638     test = GetWindow(child1, GW_OWNER);
8639     ok(!test, "wrong owner %p\n", test);
8640
8641     /* test owner/parent of child2 */
8642     test = GetParent(child2);
8643     ok(test == parent, "wrong parent %p\n", test);
8644     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8645     if(pGetAncestor) {
8646         test = pGetAncestor(child2, GA_PARENT);
8647         ok(test == parent, "wrong parent %p\n", test);
8648     }
8649     test = GetWindow(child2, GW_OWNER);
8650     ok(!test, "wrong owner %p\n", test);
8651
8652     /* test owner/parent of child3 */
8653     test = GetParent(child3);
8654     ok(test == child1, "wrong parent %p\n", test);
8655     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8656     if(pGetAncestor) {
8657         test = pGetAncestor(child3, GA_PARENT);
8658         ok(test == child1, "wrong parent %p\n", test);
8659     }
8660     test = GetWindow(child3, GW_OWNER);
8661     ok(!test, "wrong owner %p\n", test);
8662
8663     /* test owner/parent of child4 */
8664     test = GetParent(child4);
8665     ok(test == parent, "wrong parent %p\n", test);
8666     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8667     if(pGetAncestor) {
8668         test = pGetAncestor(child4, GA_PARENT);
8669         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8670     }
8671     test = GetWindow(child4, GW_OWNER);
8672     ok(test == parent, "wrong owner %p\n", test);
8673
8674     flush_sequence();
8675
8676     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8677            parent, child1, child2, child3, child4);
8678
8679     SetCapture(child4);
8680     test = GetCapture();
8681     ok(test == child4, "wrong capture window %p\n", test);
8682
8683     test_DestroyWindow_flag = TRUE;
8684     ret = DestroyWindow(parent);
8685     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8686     test_DestroyWindow_flag = FALSE;
8687     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8688
8689     ok(!IsWindow(parent), "parent still exists\n");
8690     ok(!IsWindow(child1), "child1 still exists\n");
8691     ok(!IsWindow(child2), "child2 still exists\n");
8692     ok(!IsWindow(child3), "child3 still exists\n");
8693     ok(!IsWindow(child4), "child4 still exists\n");
8694
8695     test = GetCapture();
8696     ok(!test, "wrong capture window %p\n", test);
8697 }
8698
8699
8700 static const struct message WmDispatchPaint[] = {
8701     { WM_NCPAINT, sent },
8702     { WM_GETTEXT, sent|defwinproc|optional },
8703     { WM_GETTEXT, sent|defwinproc|optional },
8704     { WM_ERASEBKGND, sent },
8705     { 0 }
8706 };
8707
8708 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8709 {
8710     if (message == WM_PAINT) return 0;
8711     return MsgCheckProcA( hwnd, message, wParam, lParam );
8712 }
8713
8714 static void test_DispatchMessage(void)
8715 {
8716     RECT rect;
8717     MSG msg;
8718     int count;
8719     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8720                                100, 100, 200, 200, 0, 0, 0, NULL);
8721     ShowWindow( hwnd, SW_SHOW );
8722     UpdateWindow( hwnd );
8723     flush_events();
8724     flush_sequence();
8725     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8726
8727     SetRect( &rect, -5, -5, 5, 5 );
8728     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8729     count = 0;
8730     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8731     {
8732         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8733         else
8734         {
8735             flush_sequence();
8736             DispatchMessage( &msg );
8737             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8738             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8739             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8740             if (++count > 10) break;
8741         }
8742     }
8743     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8744
8745     trace("now without DispatchMessage\n");
8746     flush_sequence();
8747     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8748     count = 0;
8749     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8750     {
8751         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8752         else
8753         {
8754             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8755             flush_sequence();
8756             /* this will send WM_NCCPAINT just like DispatchMessage does */
8757             GetUpdateRgn( hwnd, hrgn, TRUE );
8758             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8759             DeleteObject( hrgn );
8760             GetClientRect( hwnd, &rect );
8761             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8762             ok( !count, "Got multiple WM_PAINTs\n" );
8763             if (++count > 10) break;
8764         }
8765     }
8766     DestroyWindow(hwnd);
8767 }
8768
8769
8770 static const struct message WmUser[] = {
8771     { WM_USER, sent },
8772     { 0 }
8773 };
8774
8775 struct sendmsg_info
8776 {
8777     HWND  hwnd;
8778     DWORD timeout;
8779     DWORD ret;
8780 };
8781
8782 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8783 {
8784     struct sendmsg_info *info = arg;
8785     SetLastError( 0xdeadbeef );
8786     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8787     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8788                         broken(GetLastError() == 0),  /* win9x */
8789                         "unexpected error %d\n", GetLastError());
8790     return 0;
8791 }
8792
8793 static void wait_for_thread( HANDLE thread )
8794 {
8795     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8796     {
8797         MSG msg;
8798         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8799     }
8800 }
8801
8802 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8803 {
8804     if (message == WM_USER) Sleep(200);
8805     return MsgCheckProcA( hwnd, message, wParam, lParam );
8806 }
8807
8808 static void test_SendMessageTimeout(void)
8809 {
8810     HANDLE thread;
8811     struct sendmsg_info info;
8812     DWORD tid;
8813     BOOL is_win9x;
8814
8815     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8816                                100, 100, 200, 200, 0, 0, 0, NULL);
8817     flush_events();
8818     flush_sequence();
8819
8820     info.timeout = 1000;
8821     info.ret = 0xdeadbeef;
8822     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8823     wait_for_thread( thread );
8824     CloseHandle( thread );
8825     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8826     ok_sequence( WmUser, "WmUser", FALSE );
8827
8828     info.timeout = 1;
8829     info.ret = 0xdeadbeef;
8830     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8831     Sleep(100);  /* SendMessageTimeout should time out here */
8832     wait_for_thread( thread );
8833     CloseHandle( thread );
8834     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8835     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8836
8837     /* 0 means infinite timeout (but not on win9x) */
8838     info.timeout = 0;
8839     info.ret = 0xdeadbeef;
8840     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8841     Sleep(100);
8842     wait_for_thread( thread );
8843     CloseHandle( thread );
8844     is_win9x = !info.ret;
8845     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8846     else ok_sequence( WmUser, "WmUser", FALSE );
8847
8848     /* timeout is treated as signed despite the prototype (but not on win9x) */
8849     info.timeout = 0x7fffffff;
8850     info.ret = 0xdeadbeef;
8851     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8852     Sleep(100);
8853     wait_for_thread( thread );
8854     CloseHandle( thread );
8855     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8856     ok_sequence( WmUser, "WmUser", FALSE );
8857
8858     info.timeout = 0x80000000;
8859     info.ret = 0xdeadbeef;
8860     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8861     Sleep(100);
8862     wait_for_thread( thread );
8863     CloseHandle( thread );
8864     if (is_win9x)
8865     {
8866         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8867         ok_sequence( WmUser, "WmUser", FALSE );
8868     }
8869     else
8870     {
8871         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8872         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8873     }
8874
8875     /* now check for timeout during message processing */
8876     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8877     info.timeout = 100;
8878     info.ret = 0xdeadbeef;
8879     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8880     wait_for_thread( thread );
8881     CloseHandle( thread );
8882     /* we should time out but still get the message */
8883     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8884     ok_sequence( WmUser, "WmUser", FALSE );
8885
8886     DestroyWindow( info.hwnd );
8887 }
8888
8889
8890 /****************** edit message test *************************/
8891 #define ID_EDIT 0x1234
8892 static const struct message sl_edit_setfocus[] =
8893 {
8894     { HCBT_SETFOCUS, hook },
8895     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8896     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8897     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8898     { WM_SETFOCUS, sent|wparam, 0 },
8899     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8900     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8901     { WM_CTLCOLOREDIT, sent|parent },
8902     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8903     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8904     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8905     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8906     { 0 }
8907 };
8908 static const struct message ml_edit_setfocus[] =
8909 {
8910     { HCBT_SETFOCUS, hook },
8911     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8912     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8913     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8914     { WM_SETFOCUS, sent|wparam, 0 },
8915     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8916     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8917     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8918     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8919     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8920     { 0 }
8921 };
8922 static const struct message sl_edit_killfocus[] =
8923 {
8924     { HCBT_SETFOCUS, hook },
8925     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8926     { WM_KILLFOCUS, sent|wparam, 0 },
8927     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8928     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8929     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8930     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8931     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8932     { 0 }
8933 };
8934 static const struct message sl_edit_lbutton_dblclk[] =
8935 {
8936     { WM_LBUTTONDBLCLK, sent },
8937     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8938     { 0 }
8939 };
8940 static const struct message sl_edit_lbutton_down[] =
8941 {
8942     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8943     { HCBT_SETFOCUS, hook },
8944     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8945     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8946     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8947     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8948     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8949     { WM_CTLCOLOREDIT, sent|parent },
8950     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8951     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8952     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8953     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8954     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8955     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8956     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8957     { WM_CTLCOLOREDIT, sent|parent|optional },
8958     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8959     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8960     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8961     { 0 }
8962 };
8963 static const struct message ml_edit_lbutton_down[] =
8964 {
8965     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8966     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8967     { HCBT_SETFOCUS, hook },
8968     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8969     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8970     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8971     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8972     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8973     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8974     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8975     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8976     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8977     { 0 }
8978 };
8979 static const struct message sl_edit_lbutton_up[] =
8980 {
8981     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8982     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8983     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8984     { WM_CAPTURECHANGED, sent|defwinproc },
8985     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8986     { 0 }
8987 };
8988 static const struct message ml_edit_lbutton_up[] =
8989 {
8990     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8991     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8992     { WM_CAPTURECHANGED, sent|defwinproc },
8993     { 0 }
8994 };
8995
8996 static WNDPROC old_edit_proc;
8997
8998 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8999 {
9000     static long defwndproc_counter = 0;
9001     LRESULT ret;
9002     struct recvd_message msg;
9003
9004     if (ignore_message( message )) return 0;
9005
9006     msg.hwnd = hwnd;
9007     msg.message = message;
9008     msg.flags = sent|wparam|lparam;
9009     if (defwndproc_counter) msg.flags |= defwinproc;
9010     msg.wParam = wParam;
9011     msg.lParam = lParam;
9012     msg.descr = "edit";
9013     add_message(&msg);
9014
9015     defwndproc_counter++;
9016     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9017     defwndproc_counter--;
9018
9019     return ret;
9020 }
9021
9022 static void subclass_edit(void)
9023 {
9024     WNDCLASSA cls;
9025
9026     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9027
9028     old_edit_proc = cls.lpfnWndProc;
9029
9030     cls.hInstance = GetModuleHandle(0);
9031     cls.lpfnWndProc = edit_hook_proc;
9032     cls.lpszClassName = "my_edit_class";
9033     UnregisterClass(cls.lpszClassName, cls.hInstance);
9034     if (!RegisterClassA(&cls)) assert(0);
9035 }
9036
9037 static void test_edit_messages(void)
9038 {
9039     HWND hwnd, parent;
9040     DWORD dlg_code;
9041
9042     subclass_edit();
9043     log_all_parent_messages++;
9044
9045     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9046                              100, 100, 200, 200, 0, 0, 0, NULL);
9047     ok (parent != 0, "Failed to create parent window\n");
9048
9049     /* test single line edit */
9050     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9051                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9052     ok(hwnd != 0, "Failed to create edit window\n");
9053
9054     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9055     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9056
9057     ShowWindow(hwnd, SW_SHOW);
9058     UpdateWindow(hwnd);
9059     SetFocus(0);
9060     flush_sequence();
9061
9062     SetFocus(hwnd);
9063     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9064
9065     SetFocus(0);
9066     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9067
9068     SetFocus(0);
9069     ReleaseCapture();
9070     flush_sequence();
9071
9072     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9073     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9074
9075     SetFocus(0);
9076     ReleaseCapture();
9077     flush_sequence();
9078
9079     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9080     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9081
9082     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9083     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9084
9085     DestroyWindow(hwnd);
9086
9087     /* test multiline edit */
9088     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9089                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9090     ok(hwnd != 0, "Failed to create edit window\n");
9091
9092     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9093     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9094        "wrong dlg_code %08x\n", dlg_code);
9095
9096     ShowWindow(hwnd, SW_SHOW);
9097     UpdateWindow(hwnd);
9098     SetFocus(0);
9099     flush_sequence();
9100
9101     SetFocus(hwnd);
9102     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9103
9104     SetFocus(0);
9105     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9106
9107     SetFocus(0);
9108     ReleaseCapture();
9109     flush_sequence();
9110
9111     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9112     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9113
9114     SetFocus(0);
9115     ReleaseCapture();
9116     flush_sequence();
9117
9118     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9119     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9120
9121     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9122     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9123
9124     DestroyWindow(hwnd);
9125     DestroyWindow(parent);
9126
9127     log_all_parent_messages--;
9128 }
9129
9130 /**************************** End of Edit test ******************************/
9131
9132 static const struct message WmKeyDownSkippedSeq[] =
9133 {
9134     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9135     { 0 }
9136 };
9137 static const struct message WmKeyDownWasDownSkippedSeq[] =
9138 {
9139     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9140     { 0 }
9141 };
9142 static const struct message WmKeyUpSkippedSeq[] =
9143 {
9144     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9145     { 0 }
9146 };
9147 static const struct message WmUserKeyUpSkippedSeq[] =
9148 {
9149     { WM_USER, sent },
9150     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9151     { 0 }
9152 };
9153
9154 #define EV_STOP 0
9155 #define EV_SENDMSG 1
9156 #define EV_ACK 2
9157
9158 struct peekmsg_info
9159 {
9160     HWND  hwnd;
9161     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9162 };
9163
9164 static DWORD CALLBACK send_msg_thread_2(void *param)
9165 {
9166     DWORD ret;
9167     struct peekmsg_info *info = param;
9168
9169     trace("thread: looping\n");
9170     SetEvent(info->hevent[EV_ACK]);
9171
9172     while (1)
9173     {
9174         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9175
9176         switch (ret)
9177         {
9178         case WAIT_OBJECT_0 + EV_STOP:
9179             trace("thread: exiting\n");
9180             return 0;
9181
9182         case WAIT_OBJECT_0 + EV_SENDMSG:
9183             trace("thread: sending message\n");
9184             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
9185                 "SendNotifyMessageA failed error %u\n", GetLastError());
9186             SetEvent(info->hevent[EV_ACK]);
9187             break;
9188
9189         default:
9190             trace("unexpected return: %04x\n", ret);
9191             assert(0);
9192             break;
9193         }
9194     }
9195     return 0;
9196 }
9197
9198 static void test_PeekMessage(void)
9199 {
9200     MSG msg;
9201     HANDLE hthread;
9202     DWORD tid, qstatus;
9203     UINT qs_all_input = QS_ALLINPUT;
9204     UINT qs_input = QS_INPUT;
9205     BOOL ret;
9206     struct peekmsg_info info;
9207
9208     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9209                               100, 100, 200, 200, 0, 0, 0, NULL);
9210     assert(info.hwnd);
9211     ShowWindow(info.hwnd, SW_SHOW);
9212     UpdateWindow(info.hwnd);
9213     SetFocus(info.hwnd);
9214
9215     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9216     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9217     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9218
9219     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9220     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9221
9222     flush_events();
9223     flush_sequence();
9224
9225     SetLastError(0xdeadbeef);
9226     qstatus = GetQueueStatus(qs_all_input);
9227     if (GetLastError() == ERROR_INVALID_FLAGS)
9228     {
9229         trace("QS_RAWINPUT not supported on this platform\n");
9230         qs_all_input &= ~QS_RAWINPUT;
9231         qs_input &= ~QS_RAWINPUT;
9232     }
9233     if (qstatus & QS_POSTMESSAGE)
9234     {
9235         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9236         qstatus = GetQueueStatus(qs_all_input);
9237     }
9238     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9239
9240     trace("signalling to send message\n");
9241     SetEvent(info.hevent[EV_SENDMSG]);
9242     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9243
9244     /* pass invalid QS_xxxx flags */
9245     SetLastError(0xdeadbeef);
9246     qstatus = GetQueueStatus(0xffffffff);
9247     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9248     if (!qstatus)
9249     {
9250         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9251         qstatus = GetQueueStatus(qs_all_input);
9252     }
9253     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9254     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9255        "wrong qstatus %08x\n", qstatus);
9256
9257     msg.message = 0;
9258     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9259     ok(!ret,
9260        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9261         msg.message);
9262     ok_sequence(WmUser, "WmUser", FALSE);
9263
9264     qstatus = GetQueueStatus(qs_all_input);
9265     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9266
9267     keybd_event('N', 0, 0, 0);
9268     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9269     qstatus = GetQueueStatus(qs_all_input);
9270     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9271     {
9272         skip( "queuing key events not supported\n" );
9273         goto done;
9274     }
9275     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
9276        "wrong qstatus %08x\n", qstatus);
9277
9278     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9279     qstatus = GetQueueStatus(qs_all_input);
9280     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9281        "wrong qstatus %08x\n", qstatus);
9282
9283     InvalidateRect(info.hwnd, NULL, FALSE);
9284     qstatus = GetQueueStatus(qs_all_input);
9285     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9286        "wrong qstatus %08x\n", qstatus);
9287
9288     trace("signalling to send message\n");
9289     SetEvent(info.hevent[EV_SENDMSG]);
9290     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9291
9292     qstatus = GetQueueStatus(qs_all_input);
9293     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9294        "wrong qstatus %08x\n", qstatus);
9295
9296     msg.message = 0;
9297     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9298     if (ret && msg.message == WM_CHAR)
9299     {
9300         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9301         goto done;
9302     }
9303     ok(!ret,
9304        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9305         msg.message);
9306     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9307     {
9308         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9309         goto done;
9310     }
9311     ok_sequence(WmUser, "WmUser", FALSE);
9312
9313     qstatus = GetQueueStatus(qs_all_input);
9314     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9315        "wrong qstatus %08x\n", qstatus);
9316
9317     trace("signalling to send message\n");
9318     SetEvent(info.hevent[EV_SENDMSG]);
9319     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9320
9321     qstatus = GetQueueStatus(qs_all_input);
9322     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9323        "wrong qstatus %08x\n", qstatus);
9324
9325     msg.message = 0;
9326     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9327     ok(!ret,
9328        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9329         msg.message);
9330     ok_sequence(WmUser, "WmUser", FALSE);
9331
9332     qstatus = GetQueueStatus(qs_all_input);
9333     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9334        "wrong qstatus %08x\n", qstatus);
9335
9336     msg.message = 0;
9337     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9338     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9339        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9340        ret, msg.message, msg.wParam);
9341     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9342
9343     qstatus = GetQueueStatus(qs_all_input);
9344     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9345        "wrong qstatus %08x\n", qstatus);
9346
9347     msg.message = 0;
9348     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9349     ok(!ret,
9350        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9351         msg.message);
9352     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9353
9354     qstatus = GetQueueStatus(qs_all_input);
9355     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9356        "wrong qstatus %08x\n", qstatus);
9357
9358     msg.message = 0;
9359     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9360     ok(ret && msg.message == WM_PAINT,
9361        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9362     DispatchMessageA(&msg);
9363     ok_sequence(WmPaint, "WmPaint", FALSE);
9364
9365     qstatus = GetQueueStatus(qs_all_input);
9366     ok(qstatus == MAKELONG(0, QS_KEY),
9367        "wrong qstatus %08x\n", qstatus);
9368
9369     msg.message = 0;
9370     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9371     ok(!ret,
9372        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9373         msg.message);
9374     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9375
9376     qstatus = GetQueueStatus(qs_all_input);
9377     ok(qstatus == MAKELONG(0, QS_KEY),
9378        "wrong qstatus %08x\n", qstatus);
9379
9380     trace("signalling to send message\n");
9381     SetEvent(info.hevent[EV_SENDMSG]);
9382     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9383
9384     qstatus = GetQueueStatus(qs_all_input);
9385     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9386        "wrong qstatus %08x\n", qstatus);
9387
9388     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9389
9390     qstatus = GetQueueStatus(qs_all_input);
9391     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9392        "wrong qstatus %08x\n", qstatus);
9393
9394     msg.message = 0;
9395     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9396     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9397        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9398        ret, msg.message, msg.wParam);
9399     ok_sequence(WmUser, "WmUser", FALSE);
9400
9401     qstatus = GetQueueStatus(qs_all_input);
9402     ok(qstatus == MAKELONG(0, QS_KEY),
9403        "wrong qstatus %08x\n", qstatus);
9404
9405     msg.message = 0;
9406     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9407     ok(!ret,
9408        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9409         msg.message);
9410     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9411
9412     qstatus = GetQueueStatus(qs_all_input);
9413     ok(qstatus == MAKELONG(0, QS_KEY),
9414        "wrong qstatus %08x\n", qstatus);
9415
9416     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9417
9418     qstatus = GetQueueStatus(qs_all_input);
9419     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9420        "wrong qstatus %08x\n", qstatus);
9421
9422     trace("signalling to send message\n");
9423     SetEvent(info.hevent[EV_SENDMSG]);
9424     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9425
9426     qstatus = GetQueueStatus(qs_all_input);
9427     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9428        "wrong qstatus %08x\n", qstatus);
9429
9430     msg.message = 0;
9431     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9432     ok(!ret,
9433        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9434         msg.message);
9435     ok_sequence(WmUser, "WmUser", FALSE);
9436
9437     qstatus = GetQueueStatus(qs_all_input);
9438     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9439        "wrong qstatus %08x\n", qstatus);
9440
9441     msg.message = 0;
9442     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9443         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9444     else /* workaround for a missing QS_RAWINPUT support */
9445         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9446     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9447        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9448        ret, msg.message, msg.wParam);
9449     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9450
9451     qstatus = GetQueueStatus(qs_all_input);
9452     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9453        "wrong qstatus %08x\n", qstatus);
9454
9455     msg.message = 0;
9456     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9457         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9458     else /* workaround for a missing QS_RAWINPUT support */
9459         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9460     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9461        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9462        ret, msg.message, msg.wParam);
9463     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9464
9465     qstatus = GetQueueStatus(qs_all_input);
9466     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9467        "wrong qstatus %08x\n", qstatus);
9468
9469     msg.message = 0;
9470     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9471     ok(!ret,
9472        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9473         msg.message);
9474     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9475
9476     qstatus = GetQueueStatus(qs_all_input);
9477     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9478        "wrong qstatus %08x\n", qstatus);
9479
9480     msg.message = 0;
9481     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9482     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9483        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9484        ret, msg.message, msg.wParam);
9485     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9486
9487     qstatus = GetQueueStatus(qs_all_input);
9488     ok(qstatus == 0,
9489        "wrong qstatus %08x\n", qstatus);
9490
9491     msg.message = 0;
9492     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9493     ok(!ret,
9494        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9495         msg.message);
9496     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9497
9498     qstatus = GetQueueStatus(qs_all_input);
9499     ok(qstatus == 0,
9500        "wrong qstatus %08x\n", qstatus);
9501
9502     /* test whether presence of the quit flag in the queue affects
9503      * the queue state
9504      */
9505     PostQuitMessage(0x1234abcd);
9506
9507     qstatus = GetQueueStatus(qs_all_input);
9508     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9509        "wrong qstatus %08x\n", qstatus);
9510
9511     PostMessageA(info.hwnd, WM_USER, 0, 0);
9512
9513     qstatus = GetQueueStatus(qs_all_input);
9514     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9515        "wrong qstatus %08x\n", qstatus);
9516
9517     msg.message = 0;
9518     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9519     ok(ret && msg.message == WM_USER,
9520        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9521     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9522
9523     qstatus = GetQueueStatus(qs_all_input);
9524     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9525        "wrong qstatus %08x\n", qstatus);
9526
9527     msg.message = 0;
9528     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9529     ok(ret && msg.message == WM_QUIT,
9530        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9531     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9532     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9533     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9534
9535     qstatus = GetQueueStatus(qs_all_input);
9536 todo_wine {
9537     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9538        "wrong qstatus %08x\n", qstatus);
9539 }
9540
9541     msg.message = 0;
9542     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9543     ok(!ret,
9544        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9545         msg.message);
9546     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9547
9548     qstatus = GetQueueStatus(qs_all_input);
9549     ok(qstatus == 0,
9550        "wrong qstatus %08x\n", qstatus);
9551
9552     /* some GetMessage tests */
9553
9554     keybd_event('N', 0, 0, 0);
9555     qstatus = GetQueueStatus(qs_all_input);
9556     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9557
9558     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9559     qstatus = GetQueueStatus(qs_all_input);
9560     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9561
9562     if (qstatus)
9563     {
9564         ret = GetMessageA( &msg, 0, 0, 0 );
9565         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9566            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9567            ret, msg.message, msg.wParam);
9568         qstatus = GetQueueStatus(qs_all_input);
9569         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9570     }
9571
9572     if (qstatus)
9573     {
9574         ret = GetMessageA( &msg, 0, 0, 0 );
9575         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9576            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9577            ret, msg.message, msg.wParam);
9578         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9579         qstatus = GetQueueStatus(qs_all_input);
9580         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9581     }
9582
9583     keybd_event('N', 0, 0, 0);
9584     qstatus = GetQueueStatus(qs_all_input);
9585     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9586
9587     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9588     qstatus = GetQueueStatus(qs_all_input);
9589     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9590
9591     if (qstatus & (QS_KEY << 16))
9592     {
9593         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9594         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9595            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9596            ret, msg.message, msg.wParam);
9597         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9598         qstatus = GetQueueStatus(qs_all_input);
9599         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9600     }
9601
9602     if (qstatus)
9603     {
9604         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9605         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9606            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9607            ret, msg.message, msg.wParam);
9608         qstatus = GetQueueStatus(qs_all_input);
9609         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9610     }
9611
9612     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9613     qstatus = GetQueueStatus(qs_all_input);
9614     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9615
9616     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9617     qstatus = GetQueueStatus(qs_all_input);
9618     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9619
9620     trace("signalling to send message\n");
9621     SetEvent(info.hevent[EV_SENDMSG]);
9622     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9623     qstatus = GetQueueStatus(qs_all_input);
9624     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9625        "wrong qstatus %08x\n", qstatus);
9626
9627     if (qstatus & (QS_KEY << 16))
9628     {
9629         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9630         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9631            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9632            ret, msg.message, msg.wParam);
9633         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9634         qstatus = GetQueueStatus(qs_all_input);
9635         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9636     }
9637
9638     if (qstatus)
9639     {
9640         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9641         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9642            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9643            ret, msg.message, msg.wParam);
9644         qstatus = GetQueueStatus(qs_all_input);
9645         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9646     }
9647 done:
9648     trace("signalling to exit\n");
9649     SetEvent(info.hevent[EV_STOP]);
9650
9651     WaitForSingleObject(hthread, INFINITE);
9652
9653     CloseHandle(hthread);
9654     CloseHandle(info.hevent[0]);
9655     CloseHandle(info.hevent[1]);
9656     CloseHandle(info.hevent[2]);
9657
9658     DestroyWindow(info.hwnd);
9659 }
9660
9661 static void wait_move_event(HWND hwnd, int x, int y)
9662 {
9663     MSG msg;
9664     DWORD time;
9665     BOOL  ret;
9666     int go = 0;
9667
9668     time = GetTickCount();
9669     while (GetTickCount() - time < 200 && !go) {
9670         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9671         go  = ret && msg.pt.x > x && msg.pt.y > y;
9672         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9673     }
9674 }
9675
9676 #define STEP 5
9677 static void test_PeekMessage2(void)
9678 {
9679     HWND hwnd;
9680     BOOL ret;
9681     MSG msg;
9682     UINT message;
9683     DWORD time1, time2, time3;
9684     int x1, y1, x2, y2, x3, y3;
9685     POINT pos;
9686
9687     time1 = time2 = time3 = 0;
9688     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9689
9690     /* Initialise window and make sure it is ready for events */
9691     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9692                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9693     assert(hwnd);
9694     trace("Window for test_PeekMessage2 %p\n", hwnd);
9695     ShowWindow(hwnd, SW_SHOW);
9696     UpdateWindow(hwnd);
9697     SetFocus(hwnd);
9698     GetCursorPos(&pos);
9699     SetCursorPos(100, 100);
9700     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9701     flush_events();
9702
9703     /* Do initial mousemove, wait until we can see it
9704        and then do our test peek with PM_NOREMOVE. */
9705     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9706     wait_move_event(hwnd, 100-STEP, 100-STEP);
9707
9708     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9709     if (!ret)
9710     {
9711         skip( "queuing mouse events not supported\n" );
9712         goto done;
9713     }
9714     else
9715     {
9716         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9717         message = msg.message;
9718         time1 = msg.time;
9719         x1 = msg.pt.x;
9720         y1 = msg.pt.y;
9721         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9722     }
9723
9724     /* Allow time to advance a bit, and then simulate the user moving their
9725      * mouse around. After that we peek again with PM_NOREMOVE.
9726      * Although the previous mousemove message was never removed, the
9727      * mousemove we now peek should reflect the recent mouse movements
9728      * because the input queue will merge the move events. */
9729     Sleep(100);
9730     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9731     wait_move_event(hwnd, x1, y1);
9732
9733     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9734     ok(ret, "no message available\n");
9735     if (ret) {
9736         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9737         message = msg.message;
9738         time2 = msg.time;
9739         x2 = msg.pt.x;
9740         y2 = msg.pt.y;
9741         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9742         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9743         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9744     }
9745
9746     /* Have another go, to drive the point home */
9747     Sleep(100);
9748     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9749     wait_move_event(hwnd, x2, y2);
9750
9751     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9752     ok(ret, "no message available\n");
9753     if (ret) {
9754         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9755         message = msg.message;
9756         time3 = msg.time;
9757         x3 = msg.pt.x;
9758         y3 = msg.pt.y;
9759         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9760         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9761         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9762     }
9763
9764 done:
9765     DestroyWindow(hwnd);
9766     SetCursorPos(pos.x, pos.y);
9767     flush_events();
9768 }
9769
9770 static void test_quit_message(void)
9771 {
9772     MSG msg;
9773     BOOL ret;
9774
9775     /* test using PostQuitMessage */
9776     flush_events();
9777     PostQuitMessage(0xbeef);
9778
9779     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9780     ok(ret, "PeekMessage failed with error %d\n", 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 = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9785     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9786
9787     ret = GetMessage(&msg, NULL, 0, 0);
9788     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9789     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9790
9791     /* note: WM_QUIT message received after WM_USER message */
9792     ret = GetMessage(&msg, NULL, 0, 0);
9793     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9794     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9795     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9796
9797     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9798     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9799
9800     /* now test with PostThreadMessage - different behaviour! */
9801     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9802
9803     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9804     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9805     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9806     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9807
9808     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9809     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9810
9811     /* note: we receive the WM_QUIT message first this time */
9812     ret = GetMessage(&msg, NULL, 0, 0);
9813     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9814     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9815     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9816
9817     ret = GetMessage(&msg, NULL, 0, 0);
9818     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9819     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9820 }
9821
9822 static const struct message WmMouseHoverSeq[] = {
9823     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9824     { WM_MOUSEACTIVATE, sent|optional },
9825     { WM_TIMER, sent|optional }, /* XP sends it */
9826     { WM_SYSTIMER, sent },
9827     { WM_MOUSEHOVER, sent|wparam, 0 },
9828     { 0 }
9829 };
9830
9831 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9832 {
9833     MSG msg;
9834     DWORD start_ticks, end_ticks;
9835
9836     start_ticks = GetTickCount();
9837     /* add some deviation (50%) to cover not expected delays */
9838     start_ticks += timeout / 2;
9839
9840     do
9841     {
9842         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9843         {
9844             /* Timer proc messages are not dispatched to the window proc,
9845              * and therefore not logged.
9846              */
9847             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9848             {
9849                 struct recvd_message s_msg;
9850
9851                 s_msg.hwnd = msg.hwnd;
9852                 s_msg.message = msg.message;
9853                 s_msg.flags = sent|wparam|lparam;
9854                 s_msg.wParam = msg.wParam;
9855                 s_msg.lParam = msg.lParam;
9856                 s_msg.descr = "msg_loop";
9857                 add_message(&s_msg);
9858             }
9859             DispatchMessage(&msg);
9860         }
9861
9862         end_ticks = GetTickCount();
9863
9864         /* inject WM_MOUSEMOVE to see how it changes tracking */
9865         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9866         {
9867             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9868             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9869
9870             inject_mouse_move = FALSE;
9871         }
9872     } while (start_ticks + timeout >= end_ticks);
9873 }
9874
9875 static void test_TrackMouseEvent(void)
9876 {
9877     TRACKMOUSEEVENT tme;
9878     BOOL ret;
9879     HWND hwnd, hchild;
9880     RECT rc_parent, rc_child;
9881     UINT default_hover_time, hover_width = 0, hover_height = 0;
9882
9883 #define track_hover(track_hwnd, track_hover_time) \
9884     tme.cbSize = sizeof(tme); \
9885     tme.dwFlags = TME_HOVER; \
9886     tme.hwndTrack = track_hwnd; \
9887     tme.dwHoverTime = track_hover_time; \
9888     SetLastError(0xdeadbeef); \
9889     ret = pTrackMouseEvent(&tme); \
9890     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9891
9892 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9893     tme.cbSize = sizeof(tme); \
9894     tme.dwFlags = TME_QUERY; \
9895     tme.hwndTrack = (HWND)0xdeadbeef; \
9896     tme.dwHoverTime = 0xdeadbeef; \
9897     SetLastError(0xdeadbeef); \
9898     ret = pTrackMouseEvent(&tme); \
9899     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9900     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9901     ok(tme.dwFlags == (expected_track_flags), \
9902        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9903     ok(tme.hwndTrack == (expected_track_hwnd), \
9904        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9905     ok(tme.dwHoverTime == (expected_hover_time), \
9906        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9907
9908 #define track_hover_cancel(track_hwnd) \
9909     tme.cbSize = sizeof(tme); \
9910     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9911     tme.hwndTrack = track_hwnd; \
9912     tme.dwHoverTime = 0xdeadbeef; \
9913     SetLastError(0xdeadbeef); \
9914     ret = pTrackMouseEvent(&tme); \
9915     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9916
9917     default_hover_time = 0xdeadbeef;
9918     SetLastError(0xdeadbeef);
9919     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9920     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9921        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9922     if (!ret) default_hover_time = 400;
9923     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9924
9925     SetLastError(0xdeadbeef);
9926     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9927     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9928        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9929     if (!ret) hover_width = 4;
9930     SetLastError(0xdeadbeef);
9931     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9932     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9933        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9934     if (!ret) hover_height = 4;
9935     trace("hover rect is %u x %d\n", hover_width, hover_height);
9936
9937     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9938                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9939                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9940                           NULL, NULL, 0);
9941     assert(hwnd);
9942
9943     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9944                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9945                           50, 50, 200, 200, hwnd,
9946                           NULL, NULL, 0);
9947     assert(hchild);
9948
9949     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9950     flush_events();
9951     flush_sequence();
9952
9953     tme.cbSize = 0;
9954     tme.dwFlags = TME_QUERY;
9955     tme.hwndTrack = (HWND)0xdeadbeef;
9956     tme.dwHoverTime = 0xdeadbeef;
9957     SetLastError(0xdeadbeef);
9958     ret = pTrackMouseEvent(&tme);
9959     ok(!ret, "TrackMouseEvent should fail\n");
9960     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9961        "not expected error %u\n", GetLastError());
9962
9963     tme.cbSize = sizeof(tme);
9964     tme.dwFlags = TME_HOVER;
9965     tme.hwndTrack = (HWND)0xdeadbeef;
9966     tme.dwHoverTime = 0xdeadbeef;
9967     SetLastError(0xdeadbeef);
9968     ret = pTrackMouseEvent(&tme);
9969     ok(!ret, "TrackMouseEvent should fail\n");
9970     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9971        "not expected error %u\n", GetLastError());
9972
9973     tme.cbSize = sizeof(tme);
9974     tme.dwFlags = TME_HOVER | TME_CANCEL;
9975     tme.hwndTrack = (HWND)0xdeadbeef;
9976     tme.dwHoverTime = 0xdeadbeef;
9977     SetLastError(0xdeadbeef);
9978     ret = pTrackMouseEvent(&tme);
9979     ok(!ret, "TrackMouseEvent should fail\n");
9980     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9981        "not expected error %u\n", GetLastError());
9982
9983     GetWindowRect(hwnd, &rc_parent);
9984     GetWindowRect(hchild, &rc_child);
9985     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9986
9987     /* Process messages so that the system updates its internal current
9988      * window and hittest, otherwise TrackMouseEvent calls don't have any
9989      * effect.
9990      */
9991     flush_events();
9992     flush_sequence();
9993
9994     track_query(0, NULL, 0);
9995     track_hover(hchild, 0);
9996     track_query(0, NULL, 0);
9997
9998     flush_events();
9999     flush_sequence();
10000
10001     track_hover(hwnd, 0);
10002     tme.cbSize = sizeof(tme);
10003     tme.dwFlags = TME_QUERY;
10004     tme.hwndTrack = (HWND)0xdeadbeef;
10005     tme.dwHoverTime = 0xdeadbeef;
10006     SetLastError(0xdeadbeef);
10007     ret = pTrackMouseEvent(&tme);
10008     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10009     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10010     if (!tme.dwFlags)
10011     {
10012         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10013         DestroyWindow( hwnd );
10014         return;
10015     }
10016     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10017     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10018     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10019        tme.dwHoverTime, default_hover_time);
10020
10021     pump_msg_loop_timeout(default_hover_time, FALSE);
10022     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10023
10024     track_query(0, NULL, 0);
10025
10026     track_hover(hwnd, HOVER_DEFAULT);
10027     track_query(TME_HOVER, hwnd, default_hover_time);
10028
10029     Sleep(default_hover_time / 2);
10030     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10031     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10032
10033     track_query(TME_HOVER, hwnd, default_hover_time);
10034
10035     pump_msg_loop_timeout(default_hover_time, FALSE);
10036     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10037
10038     track_query(0, NULL, 0);
10039
10040     track_hover(hwnd, HOVER_DEFAULT);
10041     track_query(TME_HOVER, hwnd, default_hover_time);
10042
10043     pump_msg_loop_timeout(default_hover_time, TRUE);
10044     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10045
10046     track_query(0, NULL, 0);
10047
10048     track_hover(hwnd, HOVER_DEFAULT);
10049     track_query(TME_HOVER, hwnd, default_hover_time);
10050     track_hover_cancel(hwnd);
10051
10052     DestroyWindow(hwnd);
10053
10054 #undef track_hover
10055 #undef track_query
10056 #undef track_hover_cancel
10057 }
10058
10059
10060 static const struct message WmSetWindowRgn[] = {
10061     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10062     { WM_NCCALCSIZE, sent|wparam, 1 },
10063     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10064     { WM_GETTEXT, sent|defwinproc|optional },
10065     { WM_ERASEBKGND, sent|optional },
10066     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10067     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10068     { 0 }
10069 };
10070
10071 static const struct message WmSetWindowRgn_no_redraw[] = {
10072     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10073     { WM_NCCALCSIZE, sent|wparam, 1 },
10074     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10075     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10076     { 0 }
10077 };
10078
10079 static const struct message WmSetWindowRgn_clear[] = {
10080     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10081     { WM_NCCALCSIZE, sent|wparam, 1 },
10082     { WM_NCPAINT, sent|optional },
10083     { WM_GETTEXT, sent|defwinproc|optional },
10084     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10085     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10086     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10087     { WM_NCPAINT, sent|optional },
10088     { WM_GETTEXT, sent|defwinproc|optional },
10089     { WM_ERASEBKGND, sent|optional },
10090     { WM_WINDOWPOSCHANGING, sent|optional },
10091     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10092     { WM_NCPAINT, sent|optional },
10093     { WM_GETTEXT, sent|defwinproc|optional },
10094     { WM_ERASEBKGND, sent|optional },
10095     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10096     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10097     { WM_NCPAINT, sent|optional },
10098     { WM_GETTEXT, sent|defwinproc|optional },
10099     { WM_ERASEBKGND, sent|optional },
10100     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10101     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10102     { 0 }
10103 };
10104
10105 static void test_SetWindowRgn(void)
10106 {
10107     HRGN hrgn;
10108     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10109                                 100, 100, 200, 200, 0, 0, 0, NULL);
10110     ok( hwnd != 0, "Failed to create overlapped window\n" );
10111
10112     ShowWindow( hwnd, SW_SHOW );
10113     UpdateWindow( hwnd );
10114     flush_events();
10115     flush_sequence();
10116
10117     trace("testing SetWindowRgn\n");
10118     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10119     SetWindowRgn( hwnd, hrgn, TRUE );
10120     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10121
10122     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10123     SetWindowRgn( hwnd, hrgn, FALSE );
10124     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10125
10126     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10127     SetWindowRgn( hwnd, hrgn, TRUE );
10128     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10129
10130     SetWindowRgn( hwnd, 0, TRUE );
10131     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10132
10133     DestroyWindow( hwnd );
10134 }
10135
10136 /*************************** ShowWindow() test ******************************/
10137 static const struct message WmShowNormal[] = {
10138     { WM_SHOWWINDOW, sent|wparam, 1 },
10139     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10140     { HCBT_ACTIVATE, hook },
10141     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10142     { HCBT_SETFOCUS, hook },
10143     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10144     { 0 }
10145 };
10146 static const struct message WmShow[] = {
10147     { WM_SHOWWINDOW, sent|wparam, 1 },
10148     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10149     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10150     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10151     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10152     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10153     { 0 }
10154 };
10155 static const struct message WmShowNoActivate_1[] = {
10156     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10157     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10158     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10159     { WM_MOVE, sent|defwinproc|optional },
10160     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10161     { 0 }
10162 };
10163 static const struct message WmShowNoActivate_2[] = {
10164     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10165     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10166     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10167     { WM_MOVE, sent|defwinproc },
10168     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10169     { HCBT_SETFOCUS, hook|optional },
10170     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10171     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10172     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10173     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10174     { 0 }
10175 };
10176 static const struct message WmShowNA_1[] = {
10177     { WM_SHOWWINDOW, sent|wparam, 1 },
10178     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10179     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10180     { 0 }
10181 };
10182 static const struct message WmShowNA_2[] = {
10183     { WM_SHOWWINDOW, sent|wparam, 1 },
10184     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10185     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10186     { 0 }
10187 };
10188 static const struct message WmRestore_1[] = {
10189     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10190     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10191     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10192     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10193     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10194     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10195     { WM_MOVE, sent|defwinproc },
10196     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10197     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10198     { 0 }
10199 };
10200 static const struct message WmRestore_2[] = {
10201     { WM_SHOWWINDOW, sent|wparam, 1 },
10202     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10203     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10204     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10205     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10206     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10207     { 0 }
10208 };
10209 static const struct message WmRestore_3[] = {
10210     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10211     { WM_GETMINMAXINFO, sent },
10212     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10213     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10214     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10215     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10216     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10217     { WM_MOVE, sent|defwinproc },
10218     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10219     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10220     { 0 }
10221 };
10222 static const struct message WmRestore_4[] = {
10223     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10224     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10225     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10226     { WM_MOVE, sent|defwinproc|optional },
10227     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10228     { 0 }
10229 };
10230 static const struct message WmRestore_5[] = {
10231     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10232     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10233     { HCBT_ACTIVATE, hook|optional },
10234     { HCBT_SETFOCUS, hook|optional },
10235     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10236     { WM_MOVE, sent|defwinproc|optional },
10237     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10238     { 0 }
10239 };
10240 static const struct message WmHide_1[] = {
10241     { WM_SHOWWINDOW, sent|wparam, 0 },
10242     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10243     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10244     { HCBT_ACTIVATE, hook|optional },
10245     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10246     { 0 }
10247 };
10248 static const struct message WmHide_2[] = {
10249     { WM_SHOWWINDOW, sent|wparam, 0 },
10250     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10251     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10252     { HCBT_ACTIVATE, hook|optional },
10253     { 0 }
10254 };
10255 static const struct message WmHide_3[] = {
10256     { WM_SHOWWINDOW, sent|wparam, 0 },
10257     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10258     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10259     { HCBT_SETFOCUS, hook|optional },
10260     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10261     { 0 }
10262 };
10263 static const struct message WmShowMinimized_1[] = {
10264     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10265     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10266     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10267     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10268     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10269     { WM_MOVE, sent|defwinproc },
10270     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10271     { 0 }
10272 };
10273 static const struct message WmMinimize_1[] = {
10274     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10275     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10276     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10277     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10278     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10279     { WM_MOVE, sent|defwinproc },
10280     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10281     { 0 }
10282 };
10283 static const struct message WmMinimize_2[] = {
10284     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10285     { HCBT_SETFOCUS, hook|optional },
10286     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10287     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10288     { WM_MOVE, sent|defwinproc },
10289     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10290     { 0 }
10291 };
10292 static const struct message WmMinimize_3[] = {
10293     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10294     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10295     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10296     { WM_MOVE, sent|defwinproc },
10297     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10298     { 0 }
10299 };
10300 static const struct message WmShowMinNoActivate[] = {
10301     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10302     { WM_WINDOWPOSCHANGING, sent },
10303     { WM_WINDOWPOSCHANGED, sent },
10304     { WM_MOVE, sent|defwinproc|optional },
10305     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10306     { 0 }
10307 };
10308 static const struct message WmMinMax_1[] = {
10309     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10310     { 0 }
10311 };
10312 static const struct message WmMinMax_2[] = {
10313     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10314     { WM_GETMINMAXINFO, sent|optional },
10315     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10316     { HCBT_ACTIVATE, hook|optional },
10317     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10318     { HCBT_SETFOCUS, hook|optional },
10319     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10320     { WM_MOVE, sent|defwinproc|optional },
10321     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10322     { HCBT_SETFOCUS, hook|optional },
10323     { 0 }
10324 };
10325 static const struct message WmMinMax_3[] = {
10326     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10327     { HCBT_SETFOCUS, hook|optional },
10328     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10329     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10330     { WM_MOVE, sent|defwinproc|optional },
10331     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10332     { 0 }
10333 };
10334 static const struct message WmMinMax_4[] = {
10335     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10336     { 0 }
10337 };
10338 static const struct message WmShowMaximized_1[] = {
10339     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10340     { WM_GETMINMAXINFO, sent },
10341     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10342     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10343     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10344     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10345     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10346     { WM_MOVE, sent|defwinproc },
10347     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10348     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10349     { 0 }
10350 };
10351 static const struct message WmShowMaximized_2[] = {
10352     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10353     { WM_GETMINMAXINFO, sent },
10354     { WM_WINDOWPOSCHANGING, sent|optional },
10355     { HCBT_ACTIVATE, hook|optional },
10356     { WM_WINDOWPOSCHANGED, sent|optional },
10357     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10358     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10359     { WM_WINDOWPOSCHANGING, sent|optional },
10360     { HCBT_SETFOCUS, hook|optional },
10361     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10362     { WM_MOVE, sent|defwinproc },
10363     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10364     { HCBT_SETFOCUS, hook|optional },
10365     { 0 }
10366 };
10367 static const struct message WmShowMaximized_3[] = {
10368     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10369     { WM_GETMINMAXINFO, sent|optional },
10370     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10371     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10372     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10373     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10374     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10375     { WM_MOVE, sent|defwinproc|optional },
10376     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10377     { 0 }
10378 };
10379
10380 static void test_ShowWindow(void)
10381 {
10382     /* ShowWindow commands in random order */
10383     static const struct
10384     {
10385         INT cmd; /* ShowWindow command */
10386         LPARAM ret; /* ShowWindow return value */
10387         DWORD style; /* window style after the command */
10388         const struct message *msg; /* message sequence the command produces */
10389         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10390     } sw[] =
10391     {
10392 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10393 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10394 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10395 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10396 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10397 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10398 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10399 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10400 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10401 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10402 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10403 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10404 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10405 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10406 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10407 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10408 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10409 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10410 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10411 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10412 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10413 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10414 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10415 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10416 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10417 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10418 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10419 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10420 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10421 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10422 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10423 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10424 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10425 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10426 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10427 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10428 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10429 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10430 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10431 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10432 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10433 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE },
10434 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10435 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10436 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10437 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10438 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10439 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10440 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10441 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10442 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10443 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10444 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10445 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10446 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10447 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10448 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10449     };
10450     HWND hwnd;
10451     DWORD style;
10452     LPARAM ret;
10453     INT i;
10454
10455 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10456     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10457                           120, 120, 90, 90,
10458                           0, 0, 0, NULL);
10459     assert(hwnd);
10460
10461     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10462     ok(style == 0, "expected style 0, got %08x\n", style);
10463
10464     flush_events();
10465     flush_sequence();
10466
10467     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10468     {
10469         static const char * const sw_cmd_name[13] =
10470         {
10471             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10472             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10473             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10474             "SW_NORMALNA" /* 0xCC */
10475         };
10476         char comment[64];
10477         INT idx; /* index into the above array of names */
10478
10479         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10480
10481         style = GetWindowLong(hwnd, GWL_STYLE);
10482         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10483         ret = ShowWindow(hwnd, sw[i].cmd);
10484         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10485         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10486         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10487
10488         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10489         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10490
10491         flush_events();
10492         flush_sequence();
10493     }
10494
10495     DestroyWindow(hwnd);
10496 }
10497
10498 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10499 {
10500     struct recvd_message msg;
10501
10502     if (ignore_message( message )) return 0;
10503
10504     msg.hwnd = hwnd;
10505     msg.message = message;
10506     msg.flags = sent|wparam|lparam;
10507     msg.wParam = wParam;
10508     msg.lParam = lParam;
10509     msg.descr = "dialog";
10510     add_message(&msg);
10511
10512     /* calling DefDlgProc leads to a recursion under XP */
10513
10514     switch (message)
10515     {
10516     case WM_INITDIALOG:
10517     case WM_GETDLGCODE:
10518         return 0;
10519     }
10520     return 1;
10521 }
10522
10523 static const struct message WmDefDlgSetFocus_1[] = {
10524     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10525     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10526     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10527     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10528     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10529     { HCBT_SETFOCUS, hook },
10530     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10531     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10532     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10533     { WM_SETFOCUS, sent|wparam, 0 },
10534     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10535     { WM_CTLCOLOREDIT, sent },
10536     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10537     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10538     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10539     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10540     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10541     { 0 }
10542 };
10543 static const struct message WmDefDlgSetFocus_2[] = {
10544     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10545     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10546     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10547     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10548     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10549     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10550     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10551     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10552     { 0 }
10553 };
10554 /* Creation of a dialog */
10555 static const struct message WmCreateDialogParamSeq_1[] = {
10556     { HCBT_CREATEWND, hook },
10557     { WM_NCCREATE, sent },
10558     { WM_NCCALCSIZE, sent|wparam, 0 },
10559     { WM_CREATE, sent },
10560     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10561     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10562     { WM_MOVE, sent },
10563     { WM_SETFONT, sent },
10564     { WM_INITDIALOG, sent },
10565     { WM_CHANGEUISTATE, sent|optional },
10566     { 0 }
10567 };
10568 /* Creation of a dialog */
10569 static const struct message WmCreateDialogParamSeq_2[] = {
10570     { HCBT_CREATEWND, hook },
10571     { WM_NCCREATE, sent },
10572     { WM_NCCALCSIZE, sent|wparam, 0 },
10573     { WM_CREATE, sent },
10574     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10575     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10576     { WM_MOVE, sent },
10577     { WM_CHANGEUISTATE, sent|optional },
10578     { 0 }
10579 };
10580
10581 static void test_dialog_messages(void)
10582 {
10583     WNDCLASS cls;
10584     HWND hdlg, hedit1, hedit2, hfocus;
10585     LRESULT ret;
10586
10587 #define set_selection(hctl, start, end) \
10588     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10589     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10590
10591 #define check_selection(hctl, start, end) \
10592     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10593     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10594
10595     subclass_edit();
10596
10597     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10598                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10599                           0, 0, 100, 100, 0, 0, 0, NULL);
10600     ok(hdlg != 0, "Failed to create custom dialog window\n");
10601
10602     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10603                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10604                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10605     ok(hedit1 != 0, "Failed to create edit control\n");
10606     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10607                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10608                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10609     ok(hedit2 != 0, "Failed to create edit control\n");
10610
10611     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10612     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10613
10614     hfocus = GetFocus();
10615     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10616
10617     SetFocus(hedit2);
10618     hfocus = GetFocus();
10619     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10620
10621     check_selection(hedit1, 0, 0);
10622     check_selection(hedit2, 0, 0);
10623
10624     set_selection(hedit2, 0, -1);
10625     check_selection(hedit2, 0, 3);
10626
10627     SetFocus(0);
10628     hfocus = GetFocus();
10629     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10630
10631     flush_sequence();
10632     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10633     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10634     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10635
10636     hfocus = GetFocus();
10637     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10638
10639     check_selection(hedit1, 0, 5);
10640     check_selection(hedit2, 0, 3);
10641
10642     flush_sequence();
10643     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10644     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10645     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10646
10647     hfocus = GetFocus();
10648     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10649
10650     check_selection(hedit1, 0, 5);
10651     check_selection(hedit2, 0, 3);
10652
10653     EndDialog(hdlg, 0);
10654     DestroyWindow(hedit1);
10655     DestroyWindow(hedit2);
10656     DestroyWindow(hdlg);
10657     flush_sequence();
10658
10659 #undef set_selection
10660 #undef check_selection
10661
10662     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10663     cls.lpszClassName = "MyDialogClass";
10664     cls.hInstance = GetModuleHandle(0);
10665     /* need a cast since a dlgproc is used as a wndproc */
10666     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10667     if (!RegisterClass(&cls)) assert(0);
10668
10669     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10670     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10671     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10672     EndDialog(hdlg, 0);
10673     DestroyWindow(hdlg);
10674     flush_sequence();
10675
10676     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10677     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10678     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10679     EndDialog(hdlg, 0);
10680     DestroyWindow(hdlg);
10681     flush_sequence();
10682
10683     UnregisterClass(cls.lpszClassName, cls.hInstance);
10684 }
10685
10686 static void test_nullCallback(void)
10687 {
10688     HWND hwnd;
10689
10690     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10691                            100, 100, 200, 200, 0, 0, 0, NULL);
10692     ok (hwnd != 0, "Failed to create overlapped window\n");
10693
10694     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10695     flush_events();
10696     DestroyWindow(hwnd);
10697 }
10698
10699 /* SetActiveWindow( 0 ) hwnd visible */
10700 static const struct message SetActiveWindowSeq0[] =
10701 {
10702     { HCBT_ACTIVATE, hook|optional },
10703     { WM_NCACTIVATE, sent|wparam, 0 },
10704     { WM_GETTEXT, sent|defwinproc|optional },
10705     { WM_ACTIVATE, sent|wparam, 0 },
10706     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10707     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10708     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10709     { WM_KILLFOCUS, sent|optional },
10710     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10711     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10712     { WM_NCACTIVATE, sent|wparam|optional, 1 },
10713     { WM_GETTEXT, sent|defwinproc|optional },
10714     { WM_ACTIVATE, sent|wparam|optional, 1 },
10715     { HCBT_SETFOCUS, hook|optional },
10716     { WM_KILLFOCUS, sent|defwinproc|optional },
10717     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10718     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10719     { WM_IME_SETCONTEXT, sent|optional },
10720     { WM_IME_SETCONTEXT, sent|optional },
10721     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10722     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10723     { WM_SETFOCUS, sent|defwinproc|optional },
10724     { WM_GETTEXT, sent|optional },
10725     { 0 }
10726 };
10727 /* SetActiveWindow( hwnd ) hwnd visible */
10728 static const struct message SetActiveWindowSeq1[] =
10729 {
10730     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10731     { 0 }
10732 };
10733 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10734 static const struct message SetActiveWindowSeq2[] =
10735 {
10736     { HCBT_ACTIVATE, hook },
10737     { WM_NCACTIVATE, sent|wparam, 0 },
10738     { WM_GETTEXT, sent|defwinproc|optional },
10739     { WM_ACTIVATE, sent|wparam, 0 },
10740     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10741     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10742     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10743     { WM_NCPAINT, sent|optional },
10744     { WM_GETTEXT, sent|defwinproc|optional },
10745     { WM_ERASEBKGND, sent|optional },
10746     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10747     { WM_NCACTIVATE, sent|wparam, 1 },
10748     { WM_GETTEXT, sent|defwinproc|optional },
10749     { WM_ACTIVATE, sent|wparam, 1 },
10750     { HCBT_SETFOCUS, hook },
10751     { WM_KILLFOCUS, sent|defwinproc },
10752     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10753     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10754     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10755     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10756     { WM_SETFOCUS, sent|defwinproc },
10757     { WM_GETTEXT, sent|optional },
10758     { 0 }
10759 };
10760
10761 /* SetActiveWindow( hwnd ) hwnd not visible */
10762 static const struct message SetActiveWindowSeq3[] =
10763 {
10764     { HCBT_ACTIVATE, hook },
10765     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10766     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10767     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10768     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10769     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10770     { WM_ACTIVATEAPP, sent|wparam, 1 },
10771     { WM_ACTIVATEAPP, sent|wparam, 1 },
10772     { WM_NCACTIVATE, sent|wparam, 1 },
10773     { WM_ACTIVATE, sent|wparam, 1 },
10774     { HCBT_SETFOCUS, hook },
10775     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10776     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10777     { WM_SETFOCUS, sent|defwinproc },
10778     { 0 }
10779 };
10780 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10781 static const struct message SetActiveWindowSeq4[] =
10782 {
10783     { HCBT_ACTIVATE, hook },
10784     { WM_NCACTIVATE, sent|wparam, 0 },
10785     { WM_GETTEXT, sent|defwinproc|optional },
10786     { WM_ACTIVATE, sent|wparam, 0 },
10787     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10788     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10789     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10790     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10791     { WM_NCACTIVATE, sent|wparam, 1 },
10792     { WM_GETTEXT, sent|defwinproc|optional },
10793     { WM_ACTIVATE, sent|wparam, 1 },
10794     { HCBT_SETFOCUS, hook },
10795     { WM_KILLFOCUS, sent|defwinproc },
10796     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10797     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10798     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10799     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10800     { WM_SETFOCUS, sent|defwinproc },
10801     { 0 }
10802 };
10803
10804
10805 static void test_SetActiveWindow(void)
10806 {
10807     HWND hwnd, popup, ret;
10808
10809     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10810                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10811                            100, 100, 200, 200, 0, 0, 0, NULL);
10812
10813     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10814                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10815                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10816
10817     ok(hwnd != 0, "Failed to create overlapped window\n");
10818     ok(popup != 0, "Failed to create popup window\n");
10819     SetForegroundWindow( popup );
10820     flush_sequence();
10821
10822     trace("SetActiveWindow(0)\n");
10823     ret = SetActiveWindow(0);
10824     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10825     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
10826     flush_sequence();
10827
10828     trace("SetActiveWindow(hwnd), hwnd visible\n");
10829     ret = SetActiveWindow(hwnd);
10830     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10831     flush_sequence();
10832
10833     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10834     ret = SetActiveWindow(popup);
10835     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10836     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10837     flush_sequence();
10838
10839     ShowWindow(hwnd, SW_HIDE);
10840     ShowWindow(popup, SW_HIDE);
10841     flush_sequence();
10842
10843     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10844     ret = SetActiveWindow(hwnd);
10845     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
10846     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10847     flush_sequence();
10848
10849     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10850     ret = SetActiveWindow(popup);
10851     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10852     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10853     flush_sequence();
10854
10855     trace("done\n");
10856
10857     DestroyWindow(hwnd);
10858 }
10859
10860 static const struct message SetForegroundWindowSeq[] =
10861 {
10862     { WM_NCACTIVATE, sent|wparam, 0 },
10863     { WM_GETTEXT, sent|defwinproc|optional },
10864     { WM_ACTIVATE, sent|wparam, 0 },
10865     { WM_ACTIVATEAPP, sent|wparam, 0 },
10866     { WM_KILLFOCUS, sent },
10867     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10868     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10869     { 0 }
10870 };
10871
10872 static void test_SetForegroundWindow(void)
10873 {
10874     HWND hwnd;
10875
10876     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10877                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10878                            100, 100, 200, 200, 0, 0, 0, NULL);
10879     ok (hwnd != 0, "Failed to create overlapped window\n");
10880     SetForegroundWindow( hwnd );
10881     flush_sequence();
10882
10883     trace("SetForegroundWindow( 0 )\n");
10884     SetForegroundWindow( 0 );
10885     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10886     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10887     SetForegroundWindow( GetDesktopWindow() );
10888     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10889                                         "foreground top level window", FALSE);
10890     trace("done\n");
10891
10892     DestroyWindow(hwnd);
10893 }
10894
10895 static void test_dbcs_wm_char(void)
10896 {
10897     BYTE dbch[2];
10898     WCHAR wch, bad_wch;
10899     HWND hwnd, hwnd2;
10900     MSG msg;
10901     DWORD time;
10902     POINT pt;
10903     DWORD_PTR res;
10904     CPINFOEXA cpinfo;
10905     UINT i, j, k;
10906     struct message wmCharSeq[2];
10907
10908     if (!pGetCPInfoExA)
10909     {
10910         win_skip("GetCPInfoExA is not available\n");
10911         return;
10912     }
10913
10914     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10915     if (cpinfo.MaxCharSize != 2)
10916     {
10917         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10918         return;
10919     }
10920
10921     dbch[0] = dbch[1] = 0;
10922     wch = 0;
10923     bad_wch = cpinfo.UnicodeDefaultChar;
10924     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10925         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10926             for (k = 128; k <= 255; k++)
10927             {
10928                 char str[2];
10929                 WCHAR wstr[2];
10930                 str[0] = j;
10931                 str[1] = k;
10932                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10933                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10934                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10935                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10936                 {
10937                     dbch[0] = j;
10938                     dbch[1] = k;
10939                     wch = wstr[0];
10940                     break;
10941                 }
10942             }
10943
10944     if (!wch)
10945     {
10946         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10947         return;
10948     }
10949     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10950            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10951
10952     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10953                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10954     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10955                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10956     ok (hwnd != 0, "Failed to create overlapped window\n");
10957     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10958     flush_sequence();
10959
10960     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10961     wmCharSeq[0].message = WM_CHAR;
10962     wmCharSeq[0].flags = sent|wparam;
10963     wmCharSeq[0].wParam = wch;
10964
10965     /* posted message */
10966     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10967     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10968     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10969     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10970     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10971     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10972     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10973
10974     /* posted thread message */
10975     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10976     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10977     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10978     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10979     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10980     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10981     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10982
10983     /* sent message */
10984     flush_sequence();
10985     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10986     ok_sequence( WmEmptySeq, "no messages", FALSE );
10987     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10988     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10989     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10990
10991     /* sent message with timeout */
10992     flush_sequence();
10993     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10994     ok_sequence( WmEmptySeq, "no messages", FALSE );
10995     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10996     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10997     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10998
10999     /* sent message with timeout and callback */
11000     flush_sequence();
11001     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11002     ok_sequence( WmEmptySeq, "no messages", FALSE );
11003     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11004     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11005     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11006
11007     /* sent message with callback */
11008     flush_sequence();
11009     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11010     ok_sequence( WmEmptySeq, "no messages", FALSE );
11011     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11012     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11013     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11014
11015     /* direct window proc call */
11016     flush_sequence();
11017     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11018     ok_sequence( WmEmptySeq, "no messages", FALSE );
11019     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11020     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11021
11022     /* dispatch message */
11023     msg.hwnd = hwnd;
11024     msg.message = WM_CHAR;
11025     msg.wParam = dbch[0];
11026     msg.lParam = 0;
11027     DispatchMessageA( &msg );
11028     ok_sequence( WmEmptySeq, "no messages", FALSE );
11029     msg.wParam = dbch[1];
11030     DispatchMessageA( &msg );
11031     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11032
11033     /* window handle is irrelevant */
11034     flush_sequence();
11035     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11036     ok_sequence( WmEmptySeq, "no messages", FALSE );
11037     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11038     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11039     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11040
11041     /* interleaved post and send */
11042     flush_sequence();
11043     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11044     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11045     ok_sequence( WmEmptySeq, "no messages", FALSE );
11046     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11047     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11048     ok_sequence( WmEmptySeq, "no messages", FALSE );
11049     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11050     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11051     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11052     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11053     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11054     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11055     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11056
11057     /* interleaved sent message and winproc */
11058     flush_sequence();
11059     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11060     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11061     ok_sequence( WmEmptySeq, "no messages", FALSE );
11062     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11063     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11064     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11065     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11066
11067     /* interleaved winproc and dispatch */
11068     msg.hwnd = hwnd;
11069     msg.message = WM_CHAR;
11070     msg.wParam = dbch[0];
11071     msg.lParam = 0;
11072     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11073     DispatchMessageA( &msg );
11074     ok_sequence( WmEmptySeq, "no messages", FALSE );
11075     msg.wParam = dbch[1];
11076     DispatchMessageA( &msg );
11077     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11078     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11079     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11080
11081     /* interleaved sends */
11082     flush_sequence();
11083     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11084     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11085     ok_sequence( WmEmptySeq, "no messages", FALSE );
11086     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11087     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11088     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11089     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11090
11091     /* dbcs WM_CHAR */
11092     flush_sequence();
11093     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11094     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11095     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11096
11097     /* other char messages are not magic */
11098     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11099     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11100     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11101     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11102     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11103     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11104     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11105     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11106     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11107     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11108
11109     /* test retrieving messages */
11110
11111     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11112     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11113     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11114     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11115     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11116     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11117     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11118     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11119     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11120     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11121
11122     /* message filters */
11123     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11124     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11125     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11126     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11127     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11128     /* message id is filtered, hwnd is not */
11129     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
11130     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
11131     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11132     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11133     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11134     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11135
11136     /* mixing GetMessage and PostMessage */
11137     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11138     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
11139     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11140     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11141     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11142     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11143     time = msg.time;
11144     pt = msg.pt;
11145     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11146     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11147     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11148     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11149     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11150     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11151     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11152     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 );
11153     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11154
11155     /* without PM_REMOVE */
11156     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11157     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11158     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11159     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11160     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11161     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11162     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11163     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11164     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11165     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11166     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11167     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11168     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11169     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11170     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11171     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11172     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11173     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11174
11175     DestroyWindow(hwnd);
11176 }
11177
11178 #define ID_LISTBOX 0x000f
11179
11180 static const struct message wm_lb_setcursel_0[] =
11181 {
11182     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11183     { WM_CTLCOLORLISTBOX, sent|parent },
11184     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11185     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11186     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11187     { 0 }
11188 };
11189 static const struct message wm_lb_setcursel_1[] =
11190 {
11191     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11192     { WM_CTLCOLORLISTBOX, sent|parent },
11193     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11194     { WM_CTLCOLORLISTBOX, sent|parent },
11195     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11196     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11197     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11198     { 0 }
11199 };
11200 static const struct message wm_lb_setcursel_2[] =
11201 {
11202     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11203     { WM_CTLCOLORLISTBOX, sent|parent },
11204     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11205     { WM_CTLCOLORLISTBOX, sent|parent },
11206     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11207     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11208     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11209     { 0 }
11210 };
11211 static const struct message wm_lb_click_0[] =
11212 {
11213     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11214     { HCBT_SETFOCUS, hook },
11215     { WM_KILLFOCUS, sent|parent },
11216     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11217     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11218     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11219     { WM_SETFOCUS, sent|defwinproc },
11220
11221     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11222     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11223     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11224     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11225     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11226
11227     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11228     { WM_CTLCOLORLISTBOX, sent|parent },
11229     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11230     { WM_CTLCOLORLISTBOX, sent|parent },
11231     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11232     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11233
11234     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11235     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11236
11237     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11238     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11239     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11240     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11241     { 0 }
11242 };
11243 static const struct message wm_lb_deletestring[] =
11244 {
11245     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11246     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11247     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11248     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11249     { 0 }
11250 };
11251 static const struct message wm_lb_deletestring_reset[] =
11252 {
11253     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11254     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11255     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11256     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11257     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11258     { 0 }
11259 };
11260
11261 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11262
11263 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11264
11265 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11266 {
11267     static LONG defwndproc_counter = 0;
11268     LRESULT ret;
11269     struct recvd_message msg;
11270
11271     /* do not log painting messages */
11272     if (message != WM_PAINT &&
11273         message != WM_NCPAINT &&
11274         message != WM_SYNCPAINT &&
11275         message != WM_ERASEBKGND &&
11276         message != WM_NCHITTEST &&
11277         message != WM_GETTEXT &&
11278         !ignore_message( message ))
11279     {
11280         msg.hwnd = hwnd;
11281         msg.message = message;
11282         msg.flags = sent|wparam|lparam;
11283         if (defwndproc_counter) msg.flags |= defwinproc;
11284         msg.wParam = wp;
11285         msg.lParam = lp;
11286         msg.descr = "listbox";
11287         add_message(&msg);
11288     }
11289
11290     defwndproc_counter++;
11291     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11292     defwndproc_counter--;
11293
11294     return ret;
11295 }
11296
11297 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11298                                int caret_index, int top_index, int line)
11299 {
11300     LRESULT ret;
11301
11302     /* calling an orig proc helps to avoid unnecessary message logging */
11303     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11304     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11305     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11306     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11307     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11308     ok_(__FILE__, line)(ret == caret_index ||
11309                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11310                         "expected caret index %d, got %ld\n", caret_index, ret);
11311     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11312     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11313 }
11314
11315 static void test_listbox_messages(void)
11316 {
11317     HWND parent, listbox;
11318     LRESULT ret;
11319
11320     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11321                              100, 100, 200, 200, 0, 0, 0, NULL);
11322     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11323                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11324                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11325     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11326
11327     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11328
11329     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11330     ok(ret == 0, "expected 0, got %ld\n", ret);
11331     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11332     ok(ret == 1, "expected 1, got %ld\n", ret);
11333     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11334     ok(ret == 2, "expected 2, got %ld\n", ret);
11335
11336     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11337
11338     flush_sequence();
11339
11340     log_all_parent_messages++;
11341
11342     trace("selecting item 0\n");
11343     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11344     ok(ret == 0, "expected 0, got %ld\n", ret);
11345     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11346     check_lb_state(listbox, 3, 0, 0, 0);
11347     flush_sequence();
11348
11349     trace("selecting item 1\n");
11350     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11351     ok(ret == 1, "expected 1, got %ld\n", ret);
11352     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11353     check_lb_state(listbox, 3, 1, 1, 0);
11354
11355     trace("selecting item 2\n");
11356     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11357     ok(ret == 2, "expected 2, got %ld\n", ret);
11358     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11359     check_lb_state(listbox, 3, 2, 2, 0);
11360
11361     trace("clicking on item 0\n");
11362     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11363     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11364     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11365     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11366     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11367     check_lb_state(listbox, 3, 0, 0, 0);
11368     flush_sequence();
11369
11370     trace("deleting item 0\n");
11371     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11372     ok(ret == 2, "expected 2, got %ld\n", ret);
11373     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11374     check_lb_state(listbox, 2, -1, 0, 0);
11375     flush_sequence();
11376
11377     trace("deleting item 0\n");
11378     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11379     ok(ret == 1, "expected 1, got %ld\n", ret);
11380     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11381     check_lb_state(listbox, 1, -1, 0, 0);
11382     flush_sequence();
11383
11384     trace("deleting item 0\n");
11385     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11386     ok(ret == 0, "expected 0, got %ld\n", ret);
11387     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11388     check_lb_state(listbox, 0, -1, 0, 0);
11389     flush_sequence();
11390
11391     trace("deleting item 0\n");
11392     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11393     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11394     check_lb_state(listbox, 0, -1, 0, 0);
11395     flush_sequence();
11396
11397     log_all_parent_messages--;
11398
11399     DestroyWindow(listbox);
11400     DestroyWindow(parent);
11401 }
11402
11403 /*************************** Menu test ******************************/
11404 static const struct message wm_popup_menu_1[] =
11405 {
11406     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11407     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11408     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11409     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11410     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11411     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11412     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11413     { WM_INITMENU, sent|lparam, 0, 0 },
11414     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11415     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11416     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11417     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11418     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11419     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11420     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11421     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11422     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11423     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11424     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11425     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11426     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11427     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11428     { 0 }
11429 };
11430 static const struct message wm_popup_menu_2[] =
11431 {
11432     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11433     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11434     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11435     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11436     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11437     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11438     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11439     { WM_INITMENU, sent|lparam, 0, 0 },
11440     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11441     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11442     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11443     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11444     { HCBT_CREATEWND, hook },
11445     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11446                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11447     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11448     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11449     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11450     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11451     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11452     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11453     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11454     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11455     { HCBT_DESTROYWND, hook },
11456     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11457     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11458     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11459     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11460     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11461     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11462     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11463     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11464     { 0 }
11465 };
11466 static const struct message wm_popup_menu_3[] =
11467 {
11468     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11469     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11470     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11471     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11472     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11473     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11474     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11475     { WM_INITMENU, sent|lparam, 0, 0 },
11476     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11477     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11478     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11479     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11480     { HCBT_CREATEWND, hook },
11481     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11482                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11483     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11484     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11485     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11486     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11487     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11488     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11489     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11490     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11491     { HCBT_DESTROYWND, hook },
11492     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11493     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11494     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11495     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11496     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11497     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11498     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11499     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11500     { 0 }
11501 };
11502
11503 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11504 {
11505     if (message == WM_ENTERIDLE ||
11506         message == WM_INITMENU ||
11507         message == WM_INITMENUPOPUP ||
11508         message == WM_MENUSELECT ||
11509         message == WM_PARENTNOTIFY ||
11510         message == WM_ENTERMENULOOP ||
11511         message == WM_EXITMENULOOP ||
11512         message == WM_UNINITMENUPOPUP ||
11513         message == WM_KEYDOWN ||
11514         message == WM_KEYUP ||
11515         message == WM_CHAR ||
11516         message == WM_SYSKEYDOWN ||
11517         message == WM_SYSKEYUP ||
11518         message == WM_SYSCHAR ||
11519         message == WM_COMMAND ||
11520         message == WM_MENUCOMMAND)
11521     {
11522         struct recvd_message msg;
11523
11524         msg.hwnd = hwnd;
11525         msg.message = message;
11526         msg.flags = sent|wparam|lparam;
11527         msg.wParam = wp;
11528         msg.lParam = lp;
11529         msg.descr = "parent_menu_proc";
11530         add_message(&msg);
11531     }
11532
11533     return DefWindowProcA(hwnd, message, wp, lp);
11534 }
11535
11536 static void set_menu_style(HMENU hmenu, DWORD style)
11537 {
11538     MENUINFO mi;
11539     BOOL ret;
11540
11541     mi.cbSize = sizeof(mi);
11542     mi.fMask = MIM_STYLE;
11543     mi.dwStyle = style;
11544     SetLastError(0xdeadbeef);
11545     ret = pSetMenuInfo(hmenu, &mi);
11546     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11547 }
11548
11549 static DWORD get_menu_style(HMENU hmenu)
11550 {
11551     MENUINFO mi;
11552     BOOL ret;
11553
11554     mi.cbSize = sizeof(mi);
11555     mi.fMask = MIM_STYLE;
11556     mi.dwStyle = 0;
11557     SetLastError(0xdeadbeef);
11558     ret = pGetMenuInfo(hmenu, &mi);
11559     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11560
11561     return mi.dwStyle;
11562 }
11563
11564 static void test_menu_messages(void)
11565 {
11566     MSG msg;
11567     WNDCLASSA cls;
11568     HMENU hmenu, hmenu_popup;
11569     HWND hwnd;
11570     DWORD style;
11571
11572     if (!pGetMenuInfo || !pSetMenuInfo)
11573     {
11574         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11575         return;
11576     }
11577     cls.style = 0;
11578     cls.lpfnWndProc = parent_menu_proc;
11579     cls.cbClsExtra = 0;
11580     cls.cbWndExtra = 0;
11581     cls.hInstance = GetModuleHandleA(0);
11582     cls.hIcon = 0;
11583     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11584     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11585     cls.lpszMenuName = NULL;
11586     cls.lpszClassName = "TestMenuClass";
11587     UnregisterClass(cls.lpszClassName, cls.hInstance);
11588     if (!RegisterClassA(&cls)) assert(0);
11589
11590     SetLastError(0xdeadbeef);
11591     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11592                            100, 100, 200, 200, 0, 0, 0, NULL);
11593     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11594
11595     SetLastError(0xdeadbeef);
11596     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11597     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11598
11599     SetMenu(hwnd, hmenu);
11600     SetForegroundWindow( hwnd );
11601
11602     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11603     style = get_menu_style(hmenu);
11604     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11605
11606     hmenu_popup = GetSubMenu(hmenu, 0);
11607     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11608     style = get_menu_style(hmenu_popup);
11609     ok(style == 0, "expected 0, got %u\n", style);
11610
11611     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11612     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11613     style = get_menu_style(hmenu_popup);
11614     ok(style == 0, "expected 0, got %u\n", style);
11615
11616     /* Alt+E, Enter */
11617     trace("testing a popup menu command\n");
11618     flush_sequence();
11619     keybd_event(VK_MENU, 0, 0, 0);
11620     keybd_event('E', 0, 0, 0);
11621     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11622     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11623     keybd_event(VK_RETURN, 0, 0, 0);
11624     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11625     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11626     {
11627         TranslateMessage(&msg);
11628         DispatchMessage(&msg);
11629     }
11630     if (!sequence_cnt)  /* we didn't get any message */
11631     {
11632         skip( "queuing key events not supported\n" );
11633         goto done;
11634     }
11635     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
11636     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
11637     {
11638         win_skip( "menu tracking through VK_MENU not supported\n" );
11639         goto done;
11640     }
11641     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11642
11643     /* Alt+F, Right, Enter */
11644     trace("testing submenu of a popup menu command\n");
11645     flush_sequence();
11646     keybd_event(VK_MENU, 0, 0, 0);
11647     keybd_event('F', 0, 0, 0);
11648     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11649     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11650     keybd_event(VK_RIGHT, 0, 0, 0);
11651     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11652     keybd_event(VK_RETURN, 0, 0, 0);
11653     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11654     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11655     {
11656         TranslateMessage(&msg);
11657         DispatchMessage(&msg);
11658     }
11659     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11660
11661     set_menu_style(hmenu, 0);
11662     style = get_menu_style(hmenu);
11663     ok(style == 0, "expected 0, got %u\n", style);
11664
11665     hmenu_popup = GetSubMenu(hmenu, 0);
11666     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11667     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11668     style = get_menu_style(hmenu_popup);
11669     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11670
11671     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11672     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11673     style = get_menu_style(hmenu_popup);
11674     ok(style == 0, "expected 0, got %u\n", style);
11675
11676     /* Alt+F, Right, Enter */
11677     trace("testing submenu of a popup menu command\n");
11678     flush_sequence();
11679     keybd_event(VK_MENU, 0, 0, 0);
11680     keybd_event('F', 0, 0, 0);
11681     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11682     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11683     keybd_event(VK_RIGHT, 0, 0, 0);
11684     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11685     keybd_event(VK_RETURN, 0, 0, 0);
11686     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11687     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11688     {
11689         TranslateMessage(&msg);
11690         DispatchMessage(&msg);
11691     }
11692     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11693
11694 done:
11695     DestroyWindow(hwnd);
11696     DestroyMenu(hmenu);
11697 }
11698
11699
11700 static void test_paintingloop(void)
11701 {
11702     HWND hwnd;
11703
11704     paint_loop_done = 0;
11705     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11706                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11707                                 100, 100, 100, 100, 0, 0, 0, NULL );
11708     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11709     ShowWindow(hwnd,SW_NORMAL);
11710     SetFocus(hwnd);
11711
11712     while (!paint_loop_done)
11713     {
11714         MSG msg;
11715         if (PeekMessageA(&msg, 0, 0, 0, 1))
11716         {
11717             TranslateMessage(&msg);
11718             DispatchMessage(&msg);
11719         }
11720     }
11721     DestroyWindow(hwnd);
11722 }
11723
11724 static void test_defwinproc(void)
11725 {
11726     HWND hwnd;
11727     MSG msg;
11728     int gotwmquit = FALSE;
11729     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
11730     assert(hwnd);
11731     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
11732     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
11733         if( msg.message == WM_QUIT) gotwmquit = TRUE;
11734         DispatchMessageA( &msg );
11735     }
11736     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
11737     DestroyWindow( hwnd);
11738 }
11739
11740 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
11741 static void clear_clipboard_(int line, HWND hWnd)
11742 {
11743     BOOL succ;
11744     succ = OpenClipboard(hWnd);
11745     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
11746     succ = EmptyClipboard();
11747     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
11748     succ = CloseClipboard();
11749     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
11750 }
11751
11752 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
11753 static void expect_HWND_(int line, HWND expected, HWND got)
11754 {
11755     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
11756 }
11757
11758 static WNDPROC pOldViewerProc;
11759
11760 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
11761 {
11762     static BOOL recursion_guard;
11763
11764     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
11765     {
11766         recursion_guard = TRUE;
11767         clear_clipboard(hWnd);
11768         recursion_guard = FALSE;
11769     }
11770     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
11771 }
11772
11773 static void test_clipboard_viewers(void)
11774 {
11775     static struct message wm_change_cb_chain[] =
11776     {
11777         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
11778         { 0 }
11779     };
11780     static const struct message wm_clipboard_destroyed[] =
11781     {
11782         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
11783         { 0 }
11784     };
11785     static struct message wm_clipboard_changed[] =
11786     {
11787         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
11788         { 0 }
11789     };
11790     static struct message wm_clipboard_changed_and_owned[] =
11791     {
11792         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
11793         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
11794         { 0 }
11795     };
11796
11797     HINSTANCE hInst = GetModuleHandleA(NULL);
11798     HWND hWnd1, hWnd2, hWnd3;
11799     HWND hOrigViewer;
11800     HWND hRet;
11801
11802     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
11803         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
11804         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11805         GetDesktopWindow(), NULL, hInst, NULL);
11806     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
11807         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
11808         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11809         GetDesktopWindow(), NULL, hInst, NULL);
11810     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
11811         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
11812         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11813         GetDesktopWindow(), NULL, hInst, NULL);
11814     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
11815     assert(hWnd1 && hWnd2 && hWnd3);
11816
11817     flush_sequence();
11818
11819     /* Test getting the clipboard viewer and setting the viewer to NULL. */
11820     hOrigViewer = GetClipboardViewer();
11821     hRet = SetClipboardViewer(NULL);
11822     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
11823     expect_HWND(hOrigViewer, hRet);
11824     expect_HWND(NULL, GetClipboardViewer());
11825
11826     /* Test registering hWnd1 as a viewer. */
11827     hRet = SetClipboardViewer(hWnd1);
11828     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
11829     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
11830     expect_HWND(NULL, hRet);
11831     expect_HWND(hWnd1, GetClipboardViewer());
11832
11833     /* Test that changing the clipboard actually refreshes the registered viewer. */
11834     clear_clipboard(hWnd1);
11835     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
11836     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
11837
11838     /* Again, but with different owner. */
11839     clear_clipboard(hWnd2);
11840     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
11841     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
11842
11843     /* Test re-registering same window. */
11844     hRet = SetClipboardViewer(hWnd1);
11845     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
11846     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
11847     expect_HWND(hWnd1, hRet);
11848     expect_HWND(hWnd1, GetClipboardViewer());
11849
11850     /* Test ChangeClipboardChain. */
11851     ChangeClipboardChain(hWnd2, hWnd3);
11852     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
11853     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
11854     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
11855     expect_HWND(hWnd1, GetClipboardViewer());
11856
11857     ChangeClipboardChain(hWnd2, NULL);
11858     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
11859     wm_change_cb_chain[0].lParam = 0;
11860     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
11861     expect_HWND(hWnd1, GetClipboardViewer());
11862
11863     ChangeClipboardChain(NULL, hWnd2);
11864     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
11865     expect_HWND(hWnd1, GetClipboardViewer());
11866
11867     /* Actually change clipboard viewer with ChangeClipboardChain. */
11868     ChangeClipboardChain(hWnd1, hWnd2);
11869     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
11870     expect_HWND(hWnd2, GetClipboardViewer());
11871
11872     /* Test that no refresh messages are sent when viewer has unregistered. */
11873     clear_clipboard(hWnd2);
11874     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
11875
11876     /* Register hWnd1 again. */
11877     ChangeClipboardChain(hWnd2, hWnd1);
11878     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
11879     expect_HWND(hWnd1, GetClipboardViewer());
11880
11881     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
11882      * changes the clipboard. When this happens, the system shouldn't send
11883      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
11884      */
11885     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
11886     clear_clipboard(hWnd2);
11887     /* The clipboard owner is changed in recursive_viewer_proc: */
11888     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
11889     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
11890
11891     /* Test unregistering. */
11892     ChangeClipboardChain(hWnd1, NULL);
11893     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
11894     expect_HWND(NULL, GetClipboardViewer());
11895
11896     clear_clipboard(hWnd1);
11897     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
11898
11899     DestroyWindow(hWnd1);
11900     DestroyWindow(hWnd2);
11901     DestroyWindow(hWnd3);
11902     SetClipboardViewer(hOrigViewer);
11903 }
11904
11905 static void test_PostMessage(void)
11906 {
11907     static const struct
11908     {
11909         HWND hwnd;
11910         BOOL ret;
11911     } data[] =
11912     {
11913         { HWND_TOP /* 0 */, TRUE },
11914         { HWND_BROADCAST, TRUE },
11915         { HWND_BOTTOM, TRUE },
11916         { HWND_TOPMOST, TRUE },
11917         { HWND_NOTOPMOST, FALSE },
11918         { HWND_MESSAGE, FALSE },
11919         { (HWND)0xdeadbeef, FALSE }
11920     };
11921     int i;
11922     HWND hwnd;
11923     BOOL ret;
11924     MSG msg;
11925     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
11926
11927     SetLastError(0xdeadbeef);
11928     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
11929     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
11930     {
11931         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
11932         return;
11933     }
11934     assert(hwnd);
11935
11936     flush_events();
11937
11938     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
11939     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
11940
11941     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
11942     {
11943         memset(&msg, 0xab, sizeof(msg));
11944         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
11945         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
11946         if (data[i].ret)
11947         {
11948             if (data[i].hwnd)
11949                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
11950                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
11951                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
11952                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
11953             else
11954                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
11955                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
11956                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
11957                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
11958         }
11959     }
11960
11961     DestroyWindow(hwnd);
11962     flush_events();
11963 }
11964
11965 START_TEST(msg)
11966 {
11967     BOOL ret;
11968     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11969
11970     init_procs();
11971
11972     if (!RegisterWindowClasses()) assert(0);
11973
11974     if (pSetWinEventHook)
11975     {
11976         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11977                                        GetModuleHandleA(0), win_event_proc,
11978                                        0, GetCurrentThreadId(),
11979                                        WINEVENT_INCONTEXT);
11980         if (pIsWinEventHookInstalled && hEvent_hook)
11981         {
11982             UINT event;
11983             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11984                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11985         }
11986     }
11987     if (!hEvent_hook) win_skip( "no win event hook support\n" );
11988
11989     cbt_hook_thread_id = GetCurrentThreadId();
11990     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11991     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
11992
11993     test_winevents();
11994
11995     /* Fix message sequences before removing 4 lines below */
11996 #if 1
11997     if (pUnhookWinEvent && hEvent_hook)
11998     {
11999         ret = pUnhookWinEvent(hEvent_hook);
12000         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
12001         pUnhookWinEvent = 0;
12002     }
12003     hEvent_hook = 0;
12004 #endif
12005
12006     test_PostMessage();
12007     test_ShowWindow();
12008     test_PeekMessage();
12009     test_PeekMessage2();
12010     test_scrollwindowex();
12011     test_messages();
12012     test_setwindowpos();
12013     test_showwindow();
12014     invisible_parent_tests();
12015     test_mdi_messages();
12016     test_button_messages();
12017     test_static_messages();
12018     test_listbox_messages();
12019     test_combobox_messages();
12020     test_wmime_keydown_message();
12021     test_paint_messages();
12022     test_interthread_messages();
12023     test_message_conversion();
12024     test_accelerators();
12025     test_timers();
12026     test_timers_no_wnd();
12027     if (hCBT_hook) test_set_hook();
12028     test_DestroyWindow();
12029     test_DispatchMessage();
12030     test_SendMessageTimeout();
12031     test_edit_messages();
12032     test_quit_message();
12033     test_SetActiveWindow();
12034
12035     if (!pTrackMouseEvent)
12036         win_skip("TrackMouseEvent is not available\n");
12037     else
12038         test_TrackMouseEvent();
12039
12040     test_SetWindowRgn();
12041     test_sys_menu();
12042     test_dialog_messages();
12043     test_nullCallback();
12044     test_dbcs_wm_char();
12045     test_menu_messages();
12046     test_paintingloop();
12047     test_defwinproc();
12048     test_clipboard_viewers();
12049     /* keep it the last test, under Windows it tends to break the tests
12050      * which rely on active/foreground windows being correct.
12051      */
12052     test_SetForegroundWindow();
12053
12054     UnhookWindowsHookEx(hCBT_hook);
12055     if (pUnhookWinEvent && hEvent_hook)
12056     {
12057         ret = pUnhookWinEvent(hEvent_hook);
12058         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
12059         SetLastError(0xdeadbeef);
12060         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
12061         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
12062            GetLastError() == 0xdeadbeef, /* Win9x */
12063            "unexpected error %d\n", GetLastError());
12064     }
12065 }