user32/tests: Add more synchronization in the exit thread test to avoid races.
[wine] / dlls / user32 / tests / msg.c
1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004, 2005 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE        0x0800
41 #define SWP_NOCLIENTMOVE        0x1000
42 #define SWP_STATECHANGED        0x8000
43
44 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
45
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER         0x0118
52 #endif
53
54 #define WND_PARENT_ID           1
55 #define WND_POPUP_ID            2
56 #define WND_CHILD_ID            3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61
62 /* encoded DRAWITEMSTRUCT into an LPARAM */
63 typedef struct
64 {
65     union
66     {
67         struct
68         {
69             UINT type    : 4;  /* ODT_* flags */
70             UINT ctl_id  : 4;  /* Control ID */
71             UINT item_id : 4;  /* Menu item ID */
72             UINT action  : 4;  /* ODA_* flags */
73             UINT state   : 16; /* ODS_* flags */
74         } item;
75         LPARAM lp;
76     } u;
77 } DRAW_ITEM_STRUCT;
78
79 static BOOL test_DestroyWindow_flag;
80 static HWINEVENTHOOK hEvent_hook;
81 static HHOOK hCBT_hook;
82 static DWORD cbt_hook_thread_id;
83
84 static const WCHAR testWindowClassW[] =
85 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
86
87 /*
88 FIXME: add tests for these
89 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
90  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
91  WS_THICKFRAME: thick border
92  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
93  WS_BORDER (default for overlapped windows): single black border
94  none (default for child (and popup?) windows): no border
95 */
96
97 typedef enum {
98     sent=0x1,
99     posted=0x2,
100     parent=0x4,
101     wparam=0x8,
102     lparam=0x10,
103     defwinproc=0x20,
104     beginpaint=0x40,
105     optional=0x80,
106     hook=0x100,
107     winevent_hook=0x200
108 } msg_flags_t;
109
110 struct message {
111     UINT message;          /* the WM_* code */
112     msg_flags_t flags;     /* message props */
113     WPARAM wParam;         /* expected value of wParam */
114     LPARAM lParam;         /* expected value of lParam */
115     WPARAM wp_mask;        /* mask for wParam checks */
116     LPARAM lp_mask;        /* mask for lParam checks */
117 };
118
119 struct recvd_message {
120     UINT message;          /* the WM_* code */
121     msg_flags_t flags;     /* message props */
122     HWND hwnd;             /* window that received the message */
123     WPARAM wParam;         /* expected value of wParam */
124     LPARAM lParam;         /* expected value of lParam */
125     int line;              /* source line where logged */
126     const char *descr;     /* description for trace output */
127     char output[512];      /* trace output */
128 };
129
130 /* Empty message sequence */
131 static const struct message WmEmptySeq[] =
132 {
133     { 0 }
134 };
135 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
136 static const struct message WmCreateOverlappedSeq[] = {
137     { HCBT_CREATEWND, hook },
138     { WM_GETMINMAXINFO, sent },
139     { WM_NCCREATE, sent },
140     { WM_NCCALCSIZE, sent|wparam, 0 },
141     { 0x0093, sent|defwinproc|optional },
142     { 0x0094, sent|defwinproc|optional },
143     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
144     { WM_CREATE, sent },
145     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
146     { 0 }
147 };
148 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
149  * for a not visible overlapped window.
150  */
151 static const struct message WmSWP_ShowOverlappedSeq[] = {
152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
153     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
154     { WM_NCPAINT, sent|wparam|optional, 1 },
155     { WM_GETTEXT, sent|defwinproc|optional },
156     { WM_ERASEBKGND, sent|optional },
157     { HCBT_ACTIVATE, hook },
158     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
159     { WM_NOTIFYFORMAT, sent|optional },
160     { WM_QUERYUISTATE, sent|optional },
161     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
162     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
163     { WM_ACTIVATEAPP, sent|wparam, 1 },
164     { WM_NCACTIVATE, sent|wparam, 1 },
165     { WM_GETTEXT, sent|defwinproc|optional },
166     { WM_ACTIVATE, sent|wparam, 1 },
167     { HCBT_SETFOCUS, hook },
168     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
169     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
170     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
171     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
172     { WM_GETTEXT, sent|optional },
173     { WM_NCPAINT, sent|wparam|optional, 1 },
174     { WM_GETTEXT, sent|defwinproc|optional },
175     { WM_ERASEBKGND, sent|optional },
176     /* Win9x adds SWP_NOZORDER below */
177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
178     { WM_GETTEXT, sent|optional },
179     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
180     { WM_NCPAINT, sent|wparam|optional, 1 },
181     { WM_ERASEBKGND, sent|optional },
182     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
183     { WM_SYNCPAINT, sent|optional },
184     { WM_GETTITLEBARINFOEX, sent|optional },
185     { WM_PAINT, sent|optional },
186     { WM_NCPAINT, sent|beginpaint|optional },
187     { WM_GETTEXT, sent|defwinproc|optional },
188     { WM_ERASEBKGND, sent|beginpaint|optional },
189     { 0 }
190 };
191 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
192  * for a visible overlapped window.
193  */
194 static const struct message WmSWP_HideOverlappedSeq[] = {
195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
196     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
197     { HCBT_ACTIVATE, hook|optional },
198     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
199     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
200     { WM_NCACTIVATE, sent|optional },
201     { WM_ACTIVATE, sent|optional },
202     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
203     { 0 }
204 };
205
206 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
207  * for a visible overlapped window.
208  */
209 static const struct message WmSWP_ResizeSeq[] = {
210     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
211     { WM_GETMINMAXINFO, sent|defwinproc },
212     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
213     { WM_NCPAINT, sent|optional },
214     { WM_GETTEXT, sent|defwinproc|optional },
215     { WM_ERASEBKGND, sent|optional },
216     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
217     { WM_SIZE, sent|defwinproc|optional },
218     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
219     { WM_NCPAINT, sent|optional },
220     { WM_GETTEXT, sent|defwinproc|optional },
221     { WM_ERASEBKGND, sent|optional },
222     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
224     { 0 }
225 };
226
227 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
228  * for a visible popup window.
229  */
230 static const struct message WmSWP_ResizePopupSeq[] = {
231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
232     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
233     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
234     { WM_NCPAINT, sent|optional },
235     { WM_GETTEXT, sent|defwinproc|optional },
236     { WM_ERASEBKGND, sent|optional },
237     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
238     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
239     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
240     { WM_NCPAINT, sent|optional },
241     { WM_GETTEXT, sent|defwinproc|optional },
242     { WM_ERASEBKGND, sent|optional },
243     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
244     { 0 }
245 };
246
247 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
248  * for a visible overlapped window.
249  */
250 static const struct message WmSWP_MoveSeq[] = {
251     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
252     { WM_NCPAINT, sent|optional },
253     { WM_GETTEXT, sent|defwinproc|optional },
254     { WM_ERASEBKGND, sent|optional },
255     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
256     { WM_MOVE, sent|defwinproc|wparam, 0 },
257     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
258     { 0 }
259 };
260 /* Resize with SetWindowPos(SWP_NOZORDER)
261  * for a visible overlapped window
262  * SWP_NOZORDER is stripped by the logging code
263  */
264 static const struct message WmSWP_ResizeNoZOrder[] = {
265     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
266     { WM_GETMINMAXINFO, sent|defwinproc },
267     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
268     { WM_NCPAINT, sent|optional },
269     { WM_GETTEXT, sent|defwinproc|optional },
270     { WM_ERASEBKGND, sent|optional },
271     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
272       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
273     { WM_MOVE, sent|defwinproc|optional },
274     { WM_SIZE, sent|defwinproc|optional },
275     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
276     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
277     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
278     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
279     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
280     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
281     { 0 }
282 };
283
284 /* Switch visible mdi children */
285 static const struct message WmSwitchChild[] = {
286     /* Switch MDI child */
287     { WM_MDIACTIVATE, sent },/* in the MDI client */
288     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
289     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
290     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
291     /* Deactivate 2nd MDI child */
292     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
293     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
294     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
295     /* Preparing for maximize and maximaze the 1st MDI child */
296     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
297     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
298     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
299     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
300     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
301     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
302     /* Lock redraw 2nd MDI child */
303     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
304     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
305     /* Restore 2nd MDI child */
306     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
307     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
308     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
309     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
310     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
311     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
312     /* Redraw 2nd MDI child */
313     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
314     /* Redraw MDI frame */
315     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
316     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
317     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
318     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
320     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
321     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
322     { HCBT_SETFOCUS, hook },
323     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
324     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
325     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
326     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
327     { WM_SETFOCUS, sent },/* in the MDI client */
328     { HCBT_SETFOCUS, hook },
329     { WM_KILLFOCUS, sent },/* in the MDI client */
330     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
331     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
332     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
333     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
334     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
335     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
336     { 0 }
337 };
338
339 /* Switch visible not maximized mdi children */
340 static const struct message WmSwitchNotMaximizedChild[] = {
341     /* Switch not maximized MDI child */
342     { WM_MDIACTIVATE, sent },/* in the MDI client */
343     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
344     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
345     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
346     /* Deactivate 1st MDI child */
347     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
348     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
349     /* Activate 2nd MDI child */
350     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
351     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
352     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
353     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
354     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
355     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
356     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
357     { HCBT_SETFOCUS, hook },
358     { WM_KILLFOCUS, sent }, /* in the  MDI client */
359     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
360     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
361     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
362     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
363     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
364     { 0 }
365 };
366
367
368 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
369                 SWP_NOZORDER|SWP_FRAMECHANGED)
370  * for a visible overlapped window with WS_CLIPCHILDREN style set.
371  */
372 static const struct message WmSWP_FrameChanged_clip[] = {
373     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
374     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
375     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
376     { WM_GETTEXT, sent|parent|defwinproc|optional },
377     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
378     { WM_NCPAINT, sent }, /* wparam != 1 */
379     { WM_ERASEBKGND, sent },
380     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
381     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
382     { WM_PAINT, sent },
383     { 0 }
384 };
385 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
386                 SWP_NOZORDER|SWP_FRAMECHANGED)
387  * for a visible overlapped window.
388  */
389 static const struct message WmSWP_FrameChangedDeferErase[] = {
390     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
391     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
392     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
393     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
394     { WM_PAINT, sent|parent|optional },
395     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
396     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
397     { WM_PAINT, sent },
398     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
399     { WM_ERASEBKGND, sent|beginpaint|optional },
400     { 0 }
401 };
402
403 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
404                 SWP_NOZORDER|SWP_FRAMECHANGED)
405  * for a visible overlapped window without WS_CLIPCHILDREN style set.
406  */
407 static const struct message WmSWP_FrameChanged_noclip[] = {
408     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
409     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
410     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
411     { WM_GETTEXT, sent|parent|defwinproc|optional },
412     { WM_ERASEBKGND, sent|parent|optional },
413     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
414     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
415     { WM_PAINT, sent },
416     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
417     { WM_ERASEBKGND, sent|beginpaint|optional },
418     { 0 }
419 };
420
421 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
422 static const struct message WmShowOverlappedSeq[] = {
423     { WM_SHOWWINDOW, sent|wparam, 1 },
424     { WM_NCPAINT, sent|wparam|optional, 1 },
425     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
426     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
427     { WM_NCPAINT, sent|wparam|optional, 1 },
428     { WM_GETTEXT, sent|defwinproc|optional },
429     { WM_ERASEBKGND, sent|optional },
430     { HCBT_ACTIVATE, hook },
431     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
432     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
433     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
434     { WM_NCPAINT, sent|wparam|optional, 1 },
435     { WM_ACTIVATEAPP, sent|wparam, 1 },
436     { WM_NCACTIVATE, sent|wparam, 1 },
437     { WM_GETTEXT, sent|defwinproc|optional },
438     { WM_ACTIVATE, sent|wparam, 1 },
439     { HCBT_SETFOCUS, hook },
440     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
441     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
442     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
443     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
444     { WM_GETTEXT, sent|optional },
445     { WM_NCPAINT, sent|wparam|optional, 1 },
446     { WM_GETTEXT, sent|defwinproc|optional },
447     { WM_ERASEBKGND, sent|optional },
448     /* Win9x adds SWP_NOZORDER below */
449     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
450     { WM_NCCALCSIZE, sent|optional },
451     { WM_GETTEXT, sent|optional },
452     { WM_NCPAINT, sent|optional },
453     { WM_ERASEBKGND, sent|optional },
454     { WM_SYNCPAINT, sent|optional },
455 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
456        * messages. Does that mean that CreateWindow doesn't set initial
457        * window dimensions for overlapped windows?
458        */
459     { WM_SIZE, sent },
460     { WM_MOVE, sent },
461 #endif
462     { WM_PAINT, sent|optional },
463     { WM_NCPAINT, sent|beginpaint|optional },
464     { 0 }
465 };
466 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
467 static const struct message WmShowMaxOverlappedSeq[] = {
468     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
469     { WM_GETMINMAXINFO, sent },
470     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
471     { WM_GETMINMAXINFO, sent|defwinproc },
472     { WM_NCCALCSIZE, sent|wparam, TRUE },
473     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
474     { HCBT_ACTIVATE, hook },
475     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
476     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
477     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
478     { WM_ACTIVATEAPP, sent|wparam, 1 },
479     { WM_NCACTIVATE, sent|wparam, 1 },
480     { WM_GETTEXT, sent|defwinproc|optional },
481     { WM_ACTIVATE, sent|wparam, 1 },
482     { HCBT_SETFOCUS, hook },
483     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
484     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
485     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
486     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
487     { WM_GETTEXT, sent|optional },
488     { WM_NCPAINT, sent|wparam|optional, 1 },
489     { WM_GETTEXT, sent|defwinproc|optional },
490     { WM_ERASEBKGND, sent|optional },
491     /* Win9x adds SWP_NOZORDER below */
492     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
493     { WM_MOVE, sent|defwinproc },
494     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
495     { WM_GETTEXT, sent|optional },
496     { WM_NCCALCSIZE, sent|optional },
497     { WM_NCPAINT, sent|optional },
498     { WM_ERASEBKGND, sent|optional },
499     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
500     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
501     { WM_SYNCPAINT, sent|optional },
502     { WM_GETTITLEBARINFOEX, sent|optional },
503     { WM_PAINT, sent|optional },
504     { WM_NCPAINT, sent|beginpaint|optional },
505     { WM_ERASEBKGND, sent|beginpaint|optional },
506     { 0 }
507 };
508 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
509 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
510     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
511     { WM_GETTEXT, sent|optional },
512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
513     { WM_GETMINMAXINFO, sent|defwinproc },
514     { WM_NCCALCSIZE, sent|wparam, TRUE },
515     { WM_NCPAINT, sent|optional },
516     { WM_GETTEXT, sent|defwinproc|optional },
517     { WM_ERASEBKGND, sent|optional },
518     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
519     { WM_MOVE, sent|defwinproc|optional },
520     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
521     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
522     { WM_NCPAINT, sent|optional },
523     { WM_ERASEBKGND, sent|optional },
524     { WM_PAINT, sent|optional },
525     { WM_GETTITLEBARINFOEX, sent|optional },
526     { WM_NCPAINT, sent|beginpaint|optional },
527     { WM_ERASEBKGND, sent|beginpaint|optional },
528     { 0 }
529 };
530 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
531 static const struct message WmShowRestoreMinOverlappedSeq[] = {
532     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
533     { WM_QUERYOPEN, sent|optional },
534     { WM_GETTEXT, sent|optional },
535     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
536     { WM_GETMINMAXINFO, sent|defwinproc },
537     { WM_NCCALCSIZE, sent|wparam, TRUE },
538     { HCBT_ACTIVATE, hook },
539     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
540     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
541     { WM_ACTIVATEAPP, sent|wparam, 1 },
542     { WM_NCACTIVATE, sent|wparam, 1 },
543     { WM_GETTEXT, sent|defwinproc|optional },
544     { WM_ACTIVATE, sent|wparam, 1 },
545     { HCBT_SETFOCUS, hook },
546     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
547     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
548     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
549     { WM_GETTEXT, sent|optional },
550     { WM_NCPAINT, sent|wparam|optional, 1 },
551     { WM_GETTEXT, sent|defwinproc|optional },
552     { WM_ERASEBKGND, sent },
553     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
554     { WM_MOVE, sent|defwinproc },
555     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
556     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
557     { WM_NCPAINT, sent|wparam|optional, 1 },
558     { WM_ERASEBKGND, sent|optional },
559     { WM_ACTIVATE, sent|wparam, 1 },
560     { WM_GETTEXT, sent|optional },
561     { WM_PAINT, sent|optional },
562     { WM_GETTITLEBARINFOEX, sent|optional },
563     { WM_NCPAINT, sent|beginpaint|optional },
564     { WM_ERASEBKGND, sent|beginpaint|optional },
565     { 0 }
566 };
567 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
568 static const struct message WmShowMinOverlappedSeq[] = {
569     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
570     { HCBT_SETFOCUS, hook },
571     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
572     { WM_KILLFOCUS, sent },
573     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
574     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
575     { WM_GETTEXT, sent|optional },
576     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
577     { WM_GETMINMAXINFO, sent|defwinproc },
578     { WM_NCCALCSIZE, sent|wparam, TRUE },
579     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
580     { WM_NCPAINT, sent|optional },
581     { WM_GETTEXT, sent|defwinproc|optional },
582     { WM_WINDOWPOSCHANGED, sent },
583     { WM_MOVE, sent|defwinproc },
584     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
585     { WM_NCCALCSIZE, sent|optional },
586     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
587     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
588     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
589     { WM_NCACTIVATE, sent|wparam, 0 },
590     { WM_GETTEXT, sent|defwinproc|optional },
591     { WM_ACTIVATE, sent },
592     { WM_ACTIVATEAPP, sent|wparam, 0 },
593
594     /* Vista sometimes restores the window right away... */
595     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
596     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
597     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
598     { WM_QUERYOPEN, sent|optional },
599     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
600     { WM_GETMINMAXINFO, sent|optional|defwinproc },
601     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
602     { HCBT_ACTIVATE, hook|optional },
603     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
604     { WM_NCACTIVATE, sent|optional },
605     { WM_GETTEXT, sent|optional },
606     { WM_ACTIVATE, sent|optional|wparam, 1 },
607     { HCBT_SETFOCUS, hook|optional },
608     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
609     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
610     { WM_SETFOCUS, sent|optional },
611     { WM_NCPAINT, sent|optional },
612     { WM_GETTEXT, sent|defwinproc|optional },
613     { WM_ERASEBKGND, sent|optional },
614     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
615     { WM_MOVE, sent|defwinproc|optional },
616     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
617     { WM_ACTIVATE, sent|optional|wparam, 1 },
618     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
619     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
620
621     { WM_PAINT, sent|optional },
622     { WM_NCPAINT, sent|beginpaint|optional },
623     { WM_ERASEBKGND, sent|beginpaint|optional },
624     { 0 }
625 };
626 /* ShowWindow(SW_HIDE) for a visible overlapped window */
627 static const struct message WmHideOverlappedSeq[] = {
628     { WM_SHOWWINDOW, sent|wparam, 0 },
629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
630     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
631     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
632     { WM_SIZE, sent|optional }, /* XP doesn't send it */
633     { WM_MOVE, sent|optional }, /* XP doesn't send it */
634     { WM_NCACTIVATE, sent|wparam, 0 },
635     { WM_ACTIVATE, sent|wparam, 0 },
636     { WM_ACTIVATEAPP, sent|wparam, 0 },
637     { WM_KILLFOCUS, sent|wparam, 0 },
638     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
639     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
640     { 0 }
641 };
642 /* DestroyWindow for a visible overlapped window */
643 static const struct message WmDestroyOverlappedSeq[] = {
644     { HCBT_DESTROYWND, hook },
645     { 0x0090, sent|optional },
646     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
647     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
648     { 0x0090, sent|optional },
649     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
650     { WM_NCACTIVATE, sent|optional|wparam, 0 },
651     { WM_ACTIVATE, sent|optional },
652     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
653     { WM_KILLFOCUS, sent|optional|wparam, 0 },
654     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
655     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
656     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
657     { WM_DESTROY, sent },
658     { WM_NCDESTROY, sent },
659     { 0 }
660 };
661 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
662 static const struct message WmCreateMaxPopupSeq[] = {
663     { HCBT_CREATEWND, hook },
664     { WM_NCCREATE, sent },
665     { WM_NCCALCSIZE, sent|wparam, 0 },
666     { WM_CREATE, sent },
667     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
668     { WM_SIZE, sent|wparam, SIZE_RESTORED },
669     { WM_MOVE, sent },
670     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
671     { WM_GETMINMAXINFO, sent },
672     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
673     { WM_NCCALCSIZE, sent|wparam, TRUE },
674     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
675     { WM_MOVE, sent|defwinproc },
676     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
677     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
678     { WM_SHOWWINDOW, sent|wparam, 1 },
679     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
680     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
681     { HCBT_ACTIVATE, hook },
682     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
683     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
684     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
685     { WM_NCPAINT, sent|wparam|optional, 1 },
686     { WM_ERASEBKGND, sent|optional },
687     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
688     { WM_ACTIVATEAPP, sent|wparam, 1 },
689     { WM_NCACTIVATE, sent },
690     { WM_ACTIVATE, sent|wparam, 1 },
691     { HCBT_SETFOCUS, hook },
692     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
693     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
694     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
695     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
696     { WM_GETTEXT, sent|optional },
697     { WM_SYNCPAINT, sent|wparam|optional, 4 },
698     { WM_NCPAINT, sent|wparam|optional, 1 },
699     { WM_ERASEBKGND, sent|optional },
700     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
701     { WM_ERASEBKGND, sent|defwinproc|optional },
702     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
703     { 0 }
704 };
705 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
706 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
707     { HCBT_CREATEWND, hook },
708     { WM_NCCREATE, sent },
709     { WM_NCCALCSIZE, sent|wparam, 0 },
710     { WM_CREATE, sent },
711     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
712     { WM_SIZE, sent|wparam, SIZE_RESTORED },
713     { WM_MOVE, sent },
714     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
715     { WM_GETMINMAXINFO, sent },
716     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
717     { WM_NCCALCSIZE, sent|wparam, TRUE },
718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
719     { WM_MOVE, sent|defwinproc },
720     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
722     { 0 }
723 };
724 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
725 static const struct message WmShowMaxPopupResizedSeq[] = {
726     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
727     { WM_GETMINMAXINFO, sent },
728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
729     { WM_NCCALCSIZE, sent|wparam, TRUE },
730     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
731     { HCBT_ACTIVATE, hook },
732     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
733     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
734     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
735     { WM_NCPAINT, sent|wparam|optional, 1 },
736     { WM_ERASEBKGND, sent|optional },
737     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
738     { WM_ACTIVATEAPP, sent|wparam, 1 },
739     { WM_NCACTIVATE, sent },
740     { WM_ACTIVATE, sent|wparam, 1 },
741     { HCBT_SETFOCUS, hook },
742     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
743     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
744     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
745     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
746     { WM_GETTEXT, sent|optional },
747     { WM_NCPAINT, sent|wparam|optional, 1 },
748     { WM_ERASEBKGND, sent|optional },
749     { WM_WINDOWPOSCHANGED, sent },
750     /* WinNT4.0 sends WM_MOVE */
751     { WM_MOVE, sent|defwinproc|optional },
752     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
753     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
754     { 0 }
755 };
756 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
757 static const struct message WmShowMaxPopupSeq[] = {
758     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
759     { WM_GETMINMAXINFO, sent },
760     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
761     { WM_NCCALCSIZE, sent|wparam, TRUE },
762     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
763     { HCBT_ACTIVATE, hook },
764     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
765     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
766     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
767     { WM_ACTIVATEAPP, sent|wparam, 1 },
768     { WM_NCACTIVATE, sent },
769     { WM_ACTIVATE, sent|wparam, 1 },
770     { HCBT_SETFOCUS, hook },
771     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
772     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
773     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
774     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
775     { WM_GETTEXT, sent|optional },
776     { WM_SYNCPAINT, sent|wparam|optional, 4 },
777     { WM_NCPAINT, sent|wparam|optional, 1 },
778     { WM_ERASEBKGND, sent|optional },
779     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
780     { WM_ERASEBKGND, sent|defwinproc|optional },
781     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
782     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
783     { 0 }
784 };
785 /* CreateWindow(WS_VISIBLE) for popup window */
786 static const struct message WmCreatePopupSeq[] = {
787     { HCBT_CREATEWND, hook },
788     { WM_NCCREATE, sent },
789     { WM_NCCALCSIZE, sent|wparam, 0 },
790     { WM_CREATE, sent },
791     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
792     { WM_SIZE, sent|wparam, SIZE_RESTORED },
793     { WM_MOVE, sent },
794     { WM_SHOWWINDOW, sent|wparam, 1 },
795     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
796     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
797     { HCBT_ACTIVATE, hook },
798     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
799     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
800     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
801     { WM_NCPAINT, sent|wparam|optional, 1 },
802     { WM_ERASEBKGND, sent|optional },
803     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
804     { WM_ACTIVATEAPP, sent|wparam, 1 },
805     { WM_NCACTIVATE, sent },
806     { WM_ACTIVATE, sent|wparam, 1 },
807     { HCBT_SETFOCUS, hook },
808     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
809     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
810     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
811     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
812     { WM_GETTEXT, sent|optional },
813     { WM_SYNCPAINT, sent|wparam|optional, 4 },
814     { WM_NCPAINT, sent|wparam|optional, 1 },
815     { WM_ERASEBKGND, sent|optional },
816     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
817     { 0 }
818 };
819 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
820 static const struct message WmShowVisMaxPopupSeq[] = {
821     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
822     { WM_GETMINMAXINFO, sent },
823     { WM_GETTEXT, sent|optional },
824     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
825     { WM_GETTEXT, sent|optional },
826     { WM_NCCALCSIZE, sent|wparam, TRUE },
827     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
828     { WM_NCPAINT, sent|wparam|optional, 1 },
829     { WM_ERASEBKGND, sent|optional },
830     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
831     { WM_MOVE, sent|defwinproc },
832     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
833     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
834     { 0 }
835 };
836 /* CreateWindow (for a child popup window, not initially visible) */
837 static const struct message WmCreateChildPopupSeq[] = {
838     { HCBT_CREATEWND, hook },
839     { WM_NCCREATE, sent }, 
840     { WM_NCCALCSIZE, sent|wparam, 0 },
841     { WM_CREATE, sent },
842     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
843     { WM_SIZE, sent|wparam, SIZE_RESTORED },
844     { WM_MOVE, sent },
845     { 0 }
846 };
847 /* CreateWindow (for a popup window, not initially visible,
848  * which sets WS_VISIBLE in WM_CREATE handler)
849  */
850 static const struct message WmCreateInvisiblePopupSeq[] = {
851     { HCBT_CREATEWND, hook },
852     { WM_NCCREATE, sent }, 
853     { WM_NCCALCSIZE, sent|wparam, 0 },
854     { WM_CREATE, sent },
855     { WM_STYLECHANGING, sent },
856     { WM_STYLECHANGED, sent },
857     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
858     { WM_SIZE, sent|wparam, SIZE_RESTORED },
859     { WM_MOVE, sent },
860     { 0 }
861 };
862 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
863  * for a popup window with WS_VISIBLE style set
864  */
865 static const struct message WmShowVisiblePopupSeq_2[] = {
866     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
867     { 0 }
868 };
869 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
870  * for a popup window with WS_VISIBLE style set
871  */
872 static const struct message WmShowVisiblePopupSeq_3[] = {
873     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
874     { HCBT_ACTIVATE, hook },
875     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
876     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
877     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
878     { WM_NCACTIVATE, sent },
879     { WM_ACTIVATE, sent|wparam, 1 },
880     { HCBT_SETFOCUS, hook },
881     { WM_KILLFOCUS, sent|parent },
882     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
883     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
884     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
885     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
886     { WM_SETFOCUS, sent|defwinproc },
887     { WM_GETTEXT, sent|optional },
888     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
889     { 0 }
890 };
891 /* CreateWindow (for child window, not initially visible) */
892 static const struct message WmCreateChildSeq[] = {
893     { HCBT_CREATEWND, hook },
894     { WM_NCCREATE, sent }, 
895     /* child is inserted into parent's child list after WM_NCCREATE returns */
896     { WM_NCCALCSIZE, sent|wparam, 0 },
897     { WM_CREATE, sent },
898     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
899     { WM_SIZE, sent|wparam, SIZE_RESTORED },
900     { WM_MOVE, sent },
901     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
902     { 0 }
903 };
904 /* CreateWindow (for maximized child window, not initially visible) */
905 static const struct message WmCreateMaximizedChildSeq[] = {
906     { HCBT_CREATEWND, hook },
907     { WM_NCCREATE, sent }, 
908     { WM_NCCALCSIZE, sent|wparam, 0 },
909     { WM_CREATE, sent },
910     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
911     { WM_SIZE, sent|wparam, SIZE_RESTORED },
912     { WM_MOVE, sent },
913     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
914     { WM_GETMINMAXINFO, sent },
915     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
916     { WM_NCCALCSIZE, sent|wparam, 1 },
917     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
918     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
919     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
920     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
921     { 0 }
922 };
923 /* CreateWindow (for a child window, initially visible) */
924 static const struct message WmCreateVisibleChildSeq[] = {
925     { HCBT_CREATEWND, hook },
926     { WM_NCCREATE, sent }, 
927     /* child is inserted into parent's child list after WM_NCCREATE returns */
928     { WM_NCCALCSIZE, sent|wparam, 0 },
929     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
930     { WM_CREATE, sent },
931     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
932     { WM_SIZE, sent|wparam, SIZE_RESTORED },
933     { WM_MOVE, sent },
934     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
935     { WM_SHOWWINDOW, sent|wparam, 1 },
936     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
937     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
938     { WM_ERASEBKGND, sent|parent|optional },
939     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
940     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
942     { 0 }
943 };
944 /* ShowWindow(SW_SHOW) for a not visible child window */
945 static const struct message WmShowChildSeq[] = {
946     { WM_SHOWWINDOW, sent|wparam, 1 },
947     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
948     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
949     { WM_ERASEBKGND, sent|parent|optional },
950     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
951     { 0 }
952 };
953 /* ShowWindow(SW_HIDE) for a visible child window */
954 static const struct message WmHideChildSeq[] = {
955     { WM_SHOWWINDOW, sent|wparam, 0 },
956     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
957     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
958     { WM_ERASEBKGND, sent|parent|optional },
959     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
960     { 0 }
961 };
962 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
963 static const struct message WmHideChildSeq2[] = {
964     { WM_SHOWWINDOW, sent|wparam, 0 },
965     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
966     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
967     { WM_ERASEBKGND, sent|parent|optional },
968     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
969     { 0 }
970 };
971 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
972  * for a not visible child window
973  */
974 static const struct message WmShowChildSeq_2[] = {
975     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
976     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
977     { WM_CHILDACTIVATE, sent },
978     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
979     { 0 }
980 };
981 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
982  * for a not visible child window
983  */
984 static const struct message WmShowChildSeq_3[] = {
985     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
986     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
987     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
988     { 0 }
989 };
990 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
991  * for a visible child window with a caption
992  */
993 static const struct message WmShowChildSeq_4[] = {
994     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
995     { WM_CHILDACTIVATE, sent },
996     { 0 }
997 };
998 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
999 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1000     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1001     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1002     { WM_NCCALCSIZE, sent|wparam, 1 },
1003     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1004     { WM_CHILDACTIVATE, sent|optional },
1005     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1006     { WM_MOVE, sent|defwinproc },
1007     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1008     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1009     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1010     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1011     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1012     { WM_GETTEXT, sent|optional },
1013     { 0 }
1014 };
1015 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1016 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1017     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1018     { 0 }
1019 };
1020 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1021 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1022     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1023     { WM_GETMINMAXINFO, sent },
1024     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1025     { WM_NCCALCSIZE, sent|wparam, 1 },
1026     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1027     { WM_CHILDACTIVATE, sent },
1028     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1029     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1030     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1031     { 0 }
1032 };
1033 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1034 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1035     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1036     { 0 }
1037 };
1038 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1039 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1040     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1041     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1042     { WM_NCCALCSIZE, sent|wparam, 1 },
1043     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1044     { WM_CHILDACTIVATE, sent },
1045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1046     { WM_MOVE, sent|defwinproc },
1047     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1048     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1049     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1050     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1051     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1052     { WM_GETTEXT, sent|optional },
1053     { 0 }
1054 };
1055 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1056 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1057     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1058     { 0 }
1059 };
1060 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1061 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1062     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1063     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1064     { WM_NCCALCSIZE, sent|wparam, 1 },
1065     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1066     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1067     { WM_MOVE, sent|defwinproc },
1068     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1069     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1070     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1071     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1072     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1073     { WM_GETTEXT, sent|optional },
1074     { 0 }
1075 };
1076 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1077 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1078     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1079     { 0 }
1080 };
1081 /* ShowWindow(SW_SHOW) for child with invisible parent */
1082 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1083     { WM_SHOWWINDOW, sent|wparam, 1 },
1084     { 0 }
1085 };
1086 /* ShowWindow(SW_HIDE) for child with invisible parent */
1087 static const struct message WmHideChildInvisibleParentSeq[] = {
1088     { WM_SHOWWINDOW, sent|wparam, 0 },
1089     { 0 }
1090 };
1091 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1092 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1093     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1094     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1095     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1096     { 0 }
1097 };
1098 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1099 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1100     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1101     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1102     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1103     { 0 }
1104 };
1105 /* DestroyWindow for a visible child window */
1106 static const struct message WmDestroyChildSeq[] = {
1107     { HCBT_DESTROYWND, hook },
1108     { 0x0090, sent|optional },
1109     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1110     { WM_SHOWWINDOW, sent|wparam, 0 },
1111     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1112     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1113     { WM_ERASEBKGND, sent|parent|optional },
1114     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1115     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1116     { WM_KILLFOCUS, sent },
1117     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1118     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1119     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1120     { WM_SETFOCUS, sent|parent },
1121     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1122     { WM_DESTROY, sent },
1123     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1124     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1125     { WM_NCDESTROY, sent },
1126     { 0 }
1127 };
1128 /* visible child window destroyed by thread exit */
1129 static const struct message WmExitThreadSeq[] = {
1130     { WM_NCDESTROY, sent },  /* actually in grandchild */
1131     { WM_PAINT, sent|parent },
1132     { WM_ERASEBKGND, sent|parent|beginpaint },
1133     { 0 }
1134 };
1135 /* DestroyWindow for a visible child window with invisible parent */
1136 static const struct message WmDestroyInvisibleChildSeq[] = {
1137     { HCBT_DESTROYWND, hook },
1138     { 0x0090, sent|optional },
1139     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1140     { WM_SHOWWINDOW, sent|wparam, 0 },
1141     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1142     { WM_DESTROY, sent },
1143     { WM_NCDESTROY, sent },
1144     { 0 }
1145 };
1146 /* Moving the mouse in nonclient area */
1147 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1148     { WM_NCHITTEST, sent },
1149     { WM_SETCURSOR, sent },
1150     { WM_NCMOUSEMOVE, posted },
1151     { 0 }
1152 };
1153 /* Moving the mouse in client area */
1154 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1155     { WM_NCHITTEST, sent },
1156     { WM_SETCURSOR, sent },
1157     { WM_MOUSEMOVE, posted },
1158     { 0 }
1159 };
1160 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1161 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1162     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1163     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1164     { WM_GETMINMAXINFO, sent|defwinproc },
1165     { WM_ENTERSIZEMOVE, sent|defwinproc },
1166     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1167     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1168     { WM_MOVE, sent|defwinproc },
1169     { WM_EXITSIZEMOVE, sent|defwinproc },
1170     { 0 }
1171 };
1172 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1173 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1174     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1175     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1176     { WM_GETMINMAXINFO, sent|defwinproc },
1177     { WM_ENTERSIZEMOVE, sent|defwinproc },
1178     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1179     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1180     { WM_GETMINMAXINFO, sent|defwinproc },
1181     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1182     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1183     { WM_GETTEXT, sent|defwinproc },
1184     { WM_ERASEBKGND, sent|defwinproc },
1185     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1186     { WM_MOVE, sent|defwinproc },
1187     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1188     { WM_EXITSIZEMOVE, sent|defwinproc },
1189     { 0 }
1190 };
1191 /* Resizing child window with MoveWindow (32) */
1192 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1193     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1194     { WM_NCCALCSIZE, sent|wparam, 1 },
1195     { WM_ERASEBKGND, sent|parent|optional },
1196     { WM_ERASEBKGND, sent|optional },
1197     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1198     { WM_MOVE, sent|defwinproc },
1199     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1200     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1201     { 0 }
1202 };
1203 /* Clicking on inactive button */
1204 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1205     { WM_NCHITTEST, sent },
1206     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1207     { WM_MOUSEACTIVATE, sent },
1208     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1209     { WM_SETCURSOR, sent },
1210     { WM_SETCURSOR, sent|parent|defwinproc },
1211     { WM_LBUTTONDOWN, posted },
1212     { WM_KILLFOCUS, posted|parent },
1213     { WM_SETFOCUS, posted },
1214     { WM_CTLCOLORBTN, posted|parent },
1215     { BM_SETSTATE, posted },
1216     { WM_CTLCOLORBTN, posted|parent },
1217     { WM_LBUTTONUP, posted },
1218     { BM_SETSTATE, posted },
1219     { WM_CTLCOLORBTN, posted|parent },
1220     { WM_COMMAND, posted|parent },
1221     { 0 }
1222 };
1223 /* Reparenting a button (16/32) */
1224 /* The last child (button) reparented gets topmost for its new parent. */
1225 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1226     { WM_SHOWWINDOW, sent|wparam, 0 },
1227     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1228     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1229     { WM_ERASEBKGND, sent|parent },
1230     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1232     { WM_CHILDACTIVATE, sent },
1233     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1234     { WM_MOVE, sent|defwinproc },
1235     { WM_SHOWWINDOW, sent|wparam, 1 },
1236     { 0 }
1237 };
1238 /* Creation of a custom dialog (32) */
1239 static const struct message WmCreateCustomDialogSeq[] = {
1240     { HCBT_CREATEWND, hook },
1241     { WM_GETMINMAXINFO, sent },
1242     { WM_NCCREATE, sent },
1243     { WM_NCCALCSIZE, sent|wparam, 0 },
1244     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1245     { WM_CREATE, sent },
1246     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1247     { WM_NOTIFYFORMAT, sent|optional },
1248     { WM_QUERYUISTATE, sent|optional },
1249     { WM_WINDOWPOSCHANGING, sent|optional },
1250     { WM_GETMINMAXINFO, sent|optional },
1251     { WM_NCCALCSIZE, sent|optional },
1252     { WM_WINDOWPOSCHANGED, sent|optional },
1253     { WM_SHOWWINDOW, sent|wparam, 1 },
1254     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1255     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1256     { HCBT_ACTIVATE, hook },
1257     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1258
1259
1260     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1261
1262     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1263
1264     { WM_NCACTIVATE, sent },
1265     { WM_GETTEXT, sent|optional|defwinproc },
1266     { WM_GETTEXT, sent|optional|defwinproc },
1267     { WM_GETTEXT, sent|optional|defwinproc },
1268     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1269     { WM_ACTIVATE, sent|wparam, 1 },
1270     { WM_GETTEXT, sent|optional },
1271     { WM_KILLFOCUS, sent|parent },
1272     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1273     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1274     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1275     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1276     { WM_SETFOCUS, sent },
1277     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1278     { WM_NCPAINT, sent|wparam, 1 },
1279     { WM_GETTEXT, sent|optional|defwinproc },
1280     { WM_GETTEXT, sent|optional|defwinproc },
1281     { WM_ERASEBKGND, sent },
1282     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1283     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1284     { WM_GETTEXT, sent|optional },
1285     { WM_GETTEXT, sent|optional },
1286     { WM_NCCALCSIZE, sent|optional },
1287     { WM_NCPAINT, sent|optional },
1288     { WM_GETTEXT, sent|optional|defwinproc },
1289     { WM_GETTEXT, sent|optional|defwinproc },
1290     { WM_ERASEBKGND, sent|optional },
1291     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1292     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1293     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1294     { WM_MOVE, sent },
1295     { 0 }
1296 };
1297 /* Calling EndDialog for a custom dialog (32) */
1298 static const struct message WmEndCustomDialogSeq[] = {
1299     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1300     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1301     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1302     { WM_GETTEXT, sent|optional },
1303     { HCBT_ACTIVATE, hook },
1304     { WM_NCACTIVATE, sent|wparam, 0 },
1305     { WM_GETTEXT, sent|optional|defwinproc },
1306     { WM_GETTEXT, sent|optional|defwinproc },
1307     { WM_ACTIVATE, sent|wparam, 0 },
1308     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1309     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1310     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1311     { WM_GETTEXT, sent|optional|defwinproc },
1312     { WM_GETTEXT, sent|optional|defwinproc },
1313     { HCBT_SETFOCUS, hook },
1314     { WM_KILLFOCUS, sent },
1315     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1316     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1317     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1318     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1319     { WM_SETFOCUS, sent|parent|defwinproc },
1320     { 0 }
1321 };
1322 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1323 static const struct message WmShowCustomDialogSeq[] = {
1324     { WM_SHOWWINDOW, sent|wparam, 1 },
1325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1326     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1327     { HCBT_ACTIVATE, hook },
1328     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1329
1330     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1331
1332     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1333     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1334     { WM_NCACTIVATE, sent },
1335     { WM_ACTIVATE, sent|wparam, 1 },
1336     { WM_GETTEXT, sent|optional },
1337
1338     { WM_KILLFOCUS, sent|parent },
1339     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1340     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1341     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1342     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1343     { WM_SETFOCUS, sent },
1344     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1345     { WM_NCPAINT, sent|wparam, 1 },
1346     { WM_ERASEBKGND, sent },
1347     { WM_CTLCOLORDLG, sent|defwinproc },
1348     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1349     { 0 }
1350 };
1351 /* Creation and destruction of a modal dialog (32) */
1352 static const struct message WmModalDialogSeq[] = {
1353     { WM_CANCELMODE, sent|parent },
1354     { HCBT_SETFOCUS, hook },
1355     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1356     { WM_KILLFOCUS, sent|parent },
1357     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1358     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1359     { WM_ENABLE, sent|parent|wparam, 0 },
1360     { HCBT_CREATEWND, hook },
1361     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1362     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1363     { WM_SETFONT, sent },
1364     { WM_INITDIALOG, sent },
1365     { WM_CHANGEUISTATE, sent|optional },
1366     { WM_UPDATEUISTATE, sent|optional },
1367     { WM_SHOWWINDOW, sent },
1368     { HCBT_ACTIVATE, hook },
1369     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1370     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1371     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1372     { WM_NCACTIVATE, sent },
1373     { WM_GETTEXT, sent|optional },
1374     { WM_ACTIVATE, sent|wparam, 1 },
1375     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1376     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1377     { WM_NCPAINT, sent|optional },
1378     { WM_GETTEXT, sent|optional },
1379     { WM_ERASEBKGND, sent|optional },
1380     { WM_CTLCOLORDLG, sent|optional },
1381     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1382     { WM_GETTEXT, sent|optional },
1383     { WM_NCCALCSIZE, sent|optional },
1384     { WM_NCPAINT, sent|optional },
1385     { WM_GETTEXT, sent|optional },
1386     { WM_ERASEBKGND, sent|optional },
1387     { WM_CTLCOLORDLG, sent|optional },
1388     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1389     { WM_PAINT, sent|optional },
1390     { WM_CTLCOLORBTN, sent|optional },
1391     { WM_GETTITLEBARINFOEX, sent|optional },
1392     { WM_ENTERIDLE, sent|parent|optional },
1393     { WM_ENTERIDLE, sent|parent|optional },
1394     { WM_ENTERIDLE, sent|parent|optional },
1395     { WM_ENTERIDLE, sent|parent|optional },
1396     { WM_ENTERIDLE, sent|parent|optional },
1397     { WM_ENTERIDLE, sent|parent|optional },
1398     { WM_ENTERIDLE, sent|parent|optional },
1399     { WM_ENTERIDLE, sent|parent|optional },
1400     { WM_ENTERIDLE, sent|parent|optional },
1401     { WM_ENTERIDLE, sent|parent|optional },
1402     { WM_ENTERIDLE, sent|parent|optional },
1403     { WM_ENTERIDLE, sent|parent|optional },
1404     { WM_ENTERIDLE, sent|parent|optional },
1405     { WM_ENTERIDLE, sent|parent|optional },
1406     { WM_ENTERIDLE, sent|parent|optional },
1407     { WM_ENTERIDLE, sent|parent|optional },
1408     { WM_ENTERIDLE, sent|parent|optional },
1409     { WM_ENTERIDLE, sent|parent|optional },
1410     { WM_ENTERIDLE, sent|parent|optional },
1411     { WM_ENTERIDLE, sent|parent|optional },
1412     { WM_TIMER, sent },
1413     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1414     { WM_ENABLE, sent|parent|wparam, 1 },
1415     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1416     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1417     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1418     { WM_GETTEXT, sent|optional },
1419     { HCBT_ACTIVATE, hook },
1420     { WM_NCACTIVATE, sent|wparam, 0 },
1421     { WM_GETTEXT, sent|optional },
1422     { WM_ACTIVATE, sent|wparam, 0 },
1423     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1424     { WM_WINDOWPOSCHANGING, sent|optional },
1425     { WM_WINDOWPOSCHANGED, sent|optional },
1426     { HCBT_SETFOCUS, hook },
1427     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1428     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1429     { WM_SETFOCUS, sent|parent|defwinproc },
1430     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1431     { HCBT_DESTROYWND, hook },
1432     { 0x0090, sent|optional },
1433     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1434     { WM_DESTROY, sent },
1435     { WM_NCDESTROY, sent },
1436     { 0 }
1437 };
1438 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1439 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1440     /* (inside dialog proc, handling WM_INITDIALOG) */
1441     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1442     { WM_NCCALCSIZE, sent },
1443     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1444     { WM_GETTEXT, sent|defwinproc },
1445     { WM_ACTIVATE, sent|parent|wparam, 0 },
1446     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1447     { WM_WINDOWPOSCHANGING, sent|parent },
1448     { WM_NCACTIVATE, sent|wparam, 1 },
1449     { WM_ACTIVATE, sent|wparam, 1 },
1450     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1451     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1452     /* (setting focus) */
1453     { WM_SHOWWINDOW, sent|wparam, 1 },
1454     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1455     { WM_NCPAINT, sent },
1456     { WM_GETTEXT, sent|defwinproc },
1457     { WM_ERASEBKGND, sent },
1458     { WM_CTLCOLORDLG, sent|defwinproc },
1459     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1460     { WM_PAINT, sent },
1461     /* (bunch of WM_CTLCOLOR* for each control) */
1462     { WM_PAINT, sent|parent },
1463     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1464     { WM_SETCURSOR, sent|parent },
1465     { 0 }
1466 };
1467 /* SetMenu for NonVisible windows with size change*/
1468 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1469     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1470     { WM_NCCALCSIZE, sent|wparam, 1 },
1471     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1472     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1473     { WM_MOVE, sent|defwinproc },
1474     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1475     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1476     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1477     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1478     { WM_GETTEXT, sent|optional },
1479     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1480     { 0 }
1481 };
1482 /* SetMenu for NonVisible windows with no size change */
1483 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1484     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1485     { WM_NCCALCSIZE, sent|wparam, 1 },
1486     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1487     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1488     { 0 }
1489 };
1490 /* SetMenu for Visible windows with size change */
1491 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1492     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1493     { WM_NCCALCSIZE, sent|wparam, 1 },
1494     { 0x0093, sent|defwinproc|optional },
1495     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1496     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1497     { 0x0093, sent|defwinproc|optional },
1498     { 0x0093, sent|defwinproc|optional },
1499     { 0x0091, sent|defwinproc|optional },
1500     { 0x0092, sent|defwinproc|optional },
1501     { WM_GETTEXT, sent|defwinproc|optional },
1502     { WM_ERASEBKGND, sent|optional },
1503     { WM_ACTIVATE, sent|optional },
1504     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1505     { WM_MOVE, sent|defwinproc },
1506     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1507     { 0x0093, sent|optional },
1508     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1509     { 0x0093, sent|defwinproc|optional },
1510     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1511     { 0x0093, sent|defwinproc|optional },
1512     { 0x0093, sent|defwinproc|optional },
1513     { 0x0091, sent|defwinproc|optional },
1514     { 0x0092, sent|defwinproc|optional },
1515     { WM_ERASEBKGND, sent|optional },
1516     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1517     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1518     { 0 }
1519 };
1520 /* SetMenu for Visible windows with no size change */
1521 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1522     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1523     { WM_NCCALCSIZE, sent|wparam, 1 },
1524     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1525     { WM_GETTEXT, sent|defwinproc|optional },
1526     { WM_ERASEBKGND, sent|optional },
1527     { WM_ACTIVATE, sent|optional },
1528     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1529     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1530     { 0 }
1531 };
1532 /* DrawMenuBar for a visible window */
1533 static const struct message WmDrawMenuBarSeq[] =
1534 {
1535     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1536     { WM_NCCALCSIZE, sent|wparam, 1 },
1537     { 0x0093, sent|defwinproc|optional },
1538     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1539     { 0x0093, sent|defwinproc|optional },
1540     { 0x0093, sent|defwinproc|optional },
1541     { 0x0091, sent|defwinproc|optional },
1542     { 0x0092, sent|defwinproc|optional },
1543     { WM_GETTEXT, sent|defwinproc|optional },
1544     { WM_ERASEBKGND, sent|optional },
1545     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1546     { 0x0093, sent|optional },
1547     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1548     { 0 }
1549 };
1550
1551 static const struct message WmSetRedrawFalseSeq[] =
1552 {
1553     { WM_SETREDRAW, sent|wparam, 0 },
1554     { 0 }
1555 };
1556
1557 static const struct message WmSetRedrawTrueSeq[] =
1558 {
1559     { WM_SETREDRAW, sent|wparam, 1 },
1560     { 0 }
1561 };
1562
1563 static const struct message WmEnableWindowSeq_1[] =
1564 {
1565     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1566     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1567     { HCBT_SETFOCUS, hook|optional },
1568     { WM_KILLFOCUS, sent|optional },
1569     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1570     { 0 }
1571 };
1572
1573 static const struct message WmEnableWindowSeq_2[] =
1574 {
1575     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1576     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1577     { 0 }
1578 };
1579
1580 static const struct message WmGetScrollRangeSeq[] =
1581 {
1582     { SBM_GETRANGE, sent },
1583     { 0 }
1584 };
1585 static const struct message WmGetScrollInfoSeq[] =
1586 {
1587     { SBM_GETSCROLLINFO, sent },
1588     { 0 }
1589 };
1590 static const struct message WmSetScrollRangeSeq[] =
1591 {
1592     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1593        sends SBM_SETSCROLLINFO.
1594      */
1595     { SBM_SETSCROLLINFO, sent },
1596     { 0 }
1597 };
1598 /* SetScrollRange for a window without a non-client area */
1599 static const struct message WmSetScrollRangeHSeq_empty[] =
1600 {
1601     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1602     { 0 }
1603 };
1604 static const struct message WmSetScrollRangeVSeq_empty[] =
1605 {
1606     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1607     { 0 }
1608 };
1609 static const struct message WmSetScrollRangeHVSeq[] =
1610 {
1611     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1612     { WM_NCCALCSIZE, sent|wparam, 1 },
1613     { WM_GETTEXT, sent|defwinproc|optional },
1614     { WM_ERASEBKGND, sent|optional },
1615     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1616     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1617     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1618     { 0 }
1619 };
1620 /* SetScrollRange for a window with a non-client area */
1621 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1622 {
1623     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1624     { WM_NCCALCSIZE, sent|wparam, 1 },
1625     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1626     { WM_NCPAINT, sent|optional },
1627     { WM_STYLECHANGING, sent|defwinproc|optional },
1628     { WM_STYLECHANGED, sent|defwinproc|optional },
1629     { WM_STYLECHANGING, sent|defwinproc|optional },
1630     { WM_STYLECHANGED, sent|defwinproc|optional },
1631     { WM_STYLECHANGING, sent|defwinproc|optional },
1632     { WM_STYLECHANGED, sent|defwinproc|optional },
1633     { WM_STYLECHANGING, sent|defwinproc|optional },
1634     { WM_STYLECHANGED, sent|defwinproc|optional },
1635     { WM_GETTEXT, sent|defwinproc|optional },
1636     { WM_GETTEXT, sent|defwinproc|optional },
1637     { WM_ERASEBKGND, sent|optional },
1638     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1639     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1640     { WM_SIZE, sent|defwinproc|optional },
1641     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1642     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1643     { WM_GETTEXT, sent|optional },
1644     { WM_GETTEXT, sent|optional },
1645     { WM_GETTEXT, sent|optional },
1646     { WM_GETTEXT, sent|optional },
1647     { 0 }
1648 };
1649 /* test if we receive the right sequence of messages */
1650 /* after calling ShowWindow( SW_SHOWNA) */
1651 static const struct message WmSHOWNAChildInvisParInvis[] = {
1652     { WM_SHOWWINDOW, sent|wparam, 1 },
1653     { 0 }
1654 };
1655 static const struct message WmSHOWNAChildVisParInvis[] = {
1656     { WM_SHOWWINDOW, sent|wparam, 1 },
1657     { 0 }
1658 };
1659 static const struct message WmSHOWNAChildVisParVis[] = {
1660     { WM_SHOWWINDOW, sent|wparam, 1 },
1661     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1662     { 0 }
1663 };
1664 static const struct message WmSHOWNAChildInvisParVis[] = {
1665     { WM_SHOWWINDOW, sent|wparam, 1 },
1666     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1667     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1668     { WM_ERASEBKGND, sent|optional },
1669     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1670     { 0 }
1671 };
1672 static const struct message WmSHOWNATopVisible[] = {
1673     { WM_SHOWWINDOW, sent|wparam, 1 },
1674     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1675     { WM_NCPAINT, sent|wparam|optional, 1 },
1676     { WM_GETTEXT, sent|defwinproc|optional },
1677     { WM_ERASEBKGND, sent|optional },
1678     { WM_WINDOWPOSCHANGED, sent|optional },
1679     { 0 }
1680 };
1681 static const struct message WmSHOWNATopInvisible[] = {
1682     { WM_NOTIFYFORMAT, sent|optional },
1683     { WM_QUERYUISTATE, sent|optional },
1684     { WM_WINDOWPOSCHANGING, sent|optional },
1685     { WM_GETMINMAXINFO, sent|optional },
1686     { WM_NCCALCSIZE, sent|optional },
1687     { WM_WINDOWPOSCHANGED, sent|optional },
1688     { WM_SHOWWINDOW, sent|wparam, 1 },
1689     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1690     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1691     { WM_NCPAINT, sent|wparam|optional, 1 },
1692     { WM_GETTEXT, sent|defwinproc|optional },
1693     { WM_ERASEBKGND, sent|optional },
1694     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1695     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1696     { WM_NCPAINT, sent|wparam|optional, 1 },
1697     { WM_ERASEBKGND, sent|optional },
1698     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1699     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1700     { WM_MOVE, sent },
1701     { 0 }
1702 };
1703
1704 static int after_end_dialog, test_def_id;
1705 static int sequence_cnt, sequence_size;
1706 static struct recvd_message* sequence;
1707 static int log_all_parent_messages;
1708 static int paint_loop_done;
1709
1710 /* user32 functions */
1711 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1712 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1713 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1714 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1715 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1716 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1717 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1718 /* kernel32 functions */
1719 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1720
1721 static void init_procs(void)
1722 {
1723     HMODULE user32 = GetModuleHandleA("user32.dll");
1724     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1725
1726 #define GET_PROC(dll, func) \
1727     p ## func = (void*)GetProcAddress(dll, #func); \
1728     if(!p ## func) { \
1729       trace("GetProcAddress(%s) failed\n", #func); \
1730     }
1731
1732     GET_PROC(user32, GetAncestor)
1733     GET_PROC(user32, GetMenuInfo)
1734     GET_PROC(user32, NotifyWinEvent)
1735     GET_PROC(user32, SetMenuInfo)
1736     GET_PROC(user32, SetWinEventHook)
1737     GET_PROC(user32, TrackMouseEvent)
1738     GET_PROC(user32, UnhookWinEvent)
1739
1740     GET_PROC(kernel32, GetCPInfoExA)
1741
1742 #undef GET_PROC
1743 }
1744
1745 static const char *get_winpos_flags(UINT flags)
1746 {
1747     static char buffer[300];
1748
1749     buffer[0] = 0;
1750 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1751     DUMP( SWP_SHOWWINDOW );
1752     DUMP( SWP_HIDEWINDOW );
1753     DUMP( SWP_NOACTIVATE );
1754     DUMP( SWP_FRAMECHANGED );
1755     DUMP( SWP_NOCOPYBITS );
1756     DUMP( SWP_NOOWNERZORDER );
1757     DUMP( SWP_NOSENDCHANGING );
1758     DUMP( SWP_DEFERERASE );
1759     DUMP( SWP_ASYNCWINDOWPOS );
1760     DUMP( SWP_NOZORDER );
1761     DUMP( SWP_NOREDRAW );
1762     DUMP( SWP_NOSIZE );
1763     DUMP( SWP_NOMOVE );
1764     DUMP( SWP_NOCLIENTSIZE );
1765     DUMP( SWP_NOCLIENTMOVE );
1766     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1767     return buffer + 1;
1768 #undef DUMP
1769 }
1770
1771 static BOOL ignore_message( UINT message )
1772 {
1773     /* these are always ignored */
1774     return (message >= 0xc000 ||
1775             message == WM_GETICON ||
1776             message == WM_GETOBJECT ||
1777             message == WM_TIMECHANGE ||
1778             message == WM_DEVICECHANGE);
1779 }
1780
1781
1782 #define add_message(msg) add_message_(__LINE__,msg);
1783 static void add_message_(int line, const struct recvd_message *msg)
1784 {
1785     struct recvd_message *seq;
1786
1787     if (!sequence) 
1788     {
1789         sequence_size = 10;
1790         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1791     }
1792     if (sequence_cnt == sequence_size) 
1793     {
1794         sequence_size *= 2;
1795         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1796     }
1797     assert(sequence);
1798
1799     seq = &sequence[sequence_cnt];
1800     seq->hwnd = msg->hwnd;
1801     seq->message = msg->message;
1802     seq->flags = msg->flags;
1803     seq->wParam = msg->wParam;
1804     seq->lParam = msg->lParam;
1805     seq->line   = line;
1806     seq->descr  = msg->descr;
1807     seq->output[0] = 0;
1808
1809     if (msg->descr)
1810     {
1811         if (msg->flags & hook)
1812         {
1813             static const char * const CBT_code_name[10] =
1814             {
1815                 "HCBT_MOVESIZE",
1816                 "HCBT_MINMAX",
1817                 "HCBT_QS",
1818                 "HCBT_CREATEWND",
1819                 "HCBT_DESTROYWND",
1820                 "HCBT_ACTIVATE",
1821                 "HCBT_CLICKSKIPPED",
1822                 "HCBT_KEYSKIPPED",
1823                 "HCBT_SYSCOMMAND",
1824                 "HCBT_SETFOCUS"
1825             };
1826             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1827
1828             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1829                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1830         }
1831         else if (msg->flags & winevent_hook)
1832         {
1833             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1834                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1835         }
1836         else
1837         {
1838             switch (msg->message)
1839             {
1840             case WM_WINDOWPOSCHANGING:
1841             case WM_WINDOWPOSCHANGED:
1842             {
1843                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1844
1845                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1846                           msg->descr, msg->hwnd,
1847                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1848                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1849                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1850                           get_winpos_flags(winpos->flags) );
1851
1852                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1853                  * in the high word for internal purposes
1854                  */
1855                 seq->wParam = winpos->flags & 0xffff;
1856                 /* We are not interested in the flags that don't match under XP and Win9x */
1857                 seq->wParam &= ~SWP_NOZORDER;
1858                 break;
1859             }
1860
1861             case WM_DRAWITEM:
1862             {
1863                 DRAW_ITEM_STRUCT di;
1864                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1865
1866                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1867                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1868                          dis->itemID, dis->itemAction, dis->itemState);
1869
1870                 di.u.lp = 0;
1871                 di.u.item.type = dis->CtlType;
1872                 di.u.item.ctl_id = dis->CtlID;
1873                 di.u.item.item_id = dis->itemID;
1874                 di.u.item.action = dis->itemAction;
1875                 di.u.item.state = dis->itemState;
1876
1877                 seq->lParam = di.u.lp;
1878                 break;
1879             }
1880             default:
1881                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1882                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1883                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1884             }
1885             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1886                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1887         }
1888     }
1889
1890     sequence_cnt++;
1891 }
1892
1893 /* try to make sure pending X events have been processed before continuing */
1894 static void flush_events(void)
1895 {
1896     MSG msg;
1897     int diff = 200;
1898     int min_timeout = 100;
1899     DWORD time = GetTickCount() + diff;
1900
1901     while (diff > 0)
1902     {
1903         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1904         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1905         diff = time - GetTickCount();
1906     }
1907 }
1908
1909 static void flush_sequence(void)
1910 {
1911     HeapFree(GetProcessHeap(), 0, sequence);
1912     sequence = 0;
1913     sequence_cnt = sequence_size = 0;
1914 }
1915
1916 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1917 {
1918     const struct recvd_message *actual = sequence;
1919     unsigned int count = 0;
1920
1921     trace_(file, line)("Failed sequence %s:\n", context );
1922     while (expected->message && actual->message)
1923     {
1924         if (actual->output[0])
1925         {
1926             if (expected->flags & hook)
1927             {
1928                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1929                                     count, expected->message, actual->output );
1930             }
1931             else if (expected->flags & winevent_hook)
1932             {
1933                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1934                                     count, expected->message, actual->output );
1935             }
1936             else
1937             {
1938                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1939                                     count, expected->message, actual->output );
1940             }
1941         }
1942
1943         if (expected->message == actual->message)
1944         {
1945             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1946                 (expected->flags & optional))
1947             {
1948                 /* don't match messages if their defwinproc status differs */
1949                 expected++;
1950             }
1951             else
1952             {
1953                 expected++;
1954                 actual++;
1955             }
1956         }
1957         /* silently drop winevent messages if there is no support for them */
1958         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1959             expected++;
1960         else
1961         {
1962             expected++;
1963             actual++;
1964         }
1965         count++;
1966     }
1967
1968     /* optional trailing messages */
1969     while (expected->message && ((expected->flags & optional) ||
1970             ((expected->flags & winevent_hook) && !hEvent_hook)))
1971     {
1972         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1973         expected++;
1974         count++;
1975     }
1976
1977     if (expected->message)
1978     {
1979         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1980         return;
1981     }
1982
1983     while (actual->message && actual->output[0])
1984     {
1985         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
1986         actual++;
1987         count++;
1988     }
1989 }
1990
1991 #define ok_sequence( exp, contx, todo) \
1992         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1993
1994
1995 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
1996                          const char *file, int line)
1997 {
1998     static const struct recvd_message end_of_sequence;
1999     const struct message *expected = expected_list;
2000     const struct recvd_message *actual;
2001     int failcount = 0, dump = 0;
2002     unsigned int count = 0;
2003
2004     add_message(&end_of_sequence);
2005
2006     actual = sequence;
2007
2008     while (expected->message && actual->message)
2009     {
2010         if (expected->message == actual->message)
2011         {
2012             if (expected->flags & wparam)
2013             {
2014                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2015                 {
2016                     todo_wine {
2017                         failcount ++;
2018                         if (strcmp(winetest_platform, "wine")) dump++;
2019                         ok_( file, line) (FALSE,
2020                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2021                             context, count, expected->message, expected->wParam, actual->wParam);
2022                     }
2023                 }
2024                 else
2025                 {
2026                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2027                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2028                                      context, count, expected->message, expected->wParam, actual->wParam);
2029                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2030                 }
2031
2032             }
2033             if (expected->flags & lparam)
2034             {
2035                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2036                 {
2037                     todo_wine {
2038                         failcount ++;
2039                         if (strcmp(winetest_platform, "wine")) dump++;
2040                         ok_( file, line) (FALSE,
2041                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2042                             context, count, expected->message, expected->lParam, actual->lParam);
2043                     }
2044                 }
2045                 else
2046                 {
2047                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2048                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2049                                      context, count, expected->message, expected->lParam, actual->lParam);
2050                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2051                 }
2052             }
2053             if ((expected->flags & optional) &&
2054                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2055             {
2056                 /* don't match optional messages if their defwinproc or parent status differs */
2057                 expected++;
2058                 count++;
2059                 continue;
2060             }
2061             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2062             {
2063                     todo_wine {
2064                         failcount ++;
2065                         if (strcmp(winetest_platform, "wine")) dump++;
2066                         ok_( file, line) (FALSE,
2067                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2068                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2069                     }
2070             }
2071             else
2072             {
2073                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2074                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2075                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2076                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2077             }
2078
2079             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2080                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2081                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2082             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2083
2084             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2085                 "%s: %u: the msg 0x%04x should have been %s\n",
2086                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2087             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2088
2089             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2090                 "%s: %u: the msg 0x%04x was expected in %s\n",
2091                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2092             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2093
2094             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2095                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2096                 context, count, expected->message);
2097             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2098
2099             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2100                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2101                 context, count, expected->message);
2102             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2103
2104             expected++;
2105             actual++;
2106         }
2107         /* silently drop hook messages if there is no support for them */
2108         else if ((expected->flags & optional) ||
2109                  ((expected->flags & hook) && !hCBT_hook) ||
2110                  ((expected->flags & winevent_hook) && !hEvent_hook))
2111             expected++;
2112         else if (todo)
2113         {
2114             failcount++;
2115             todo_wine {
2116                 if (strcmp(winetest_platform, "wine")) dump++;
2117                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2118                                   context, count, expected->message, actual->message);
2119             }
2120             goto done;
2121         }
2122         else
2123         {
2124             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2125                               context, count, expected->message, actual->message);
2126             dump++;
2127             expected++;
2128             actual++;
2129         }
2130         count++;
2131     }
2132
2133     /* skip all optional trailing messages */
2134     while (expected->message && ((expected->flags & optional) ||
2135                                  ((expected->flags & hook) && !hCBT_hook) ||
2136                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2137         expected++;
2138
2139     if (todo)
2140     {
2141         todo_wine {
2142             if (expected->message || actual->message) {
2143                 failcount++;
2144                 if (strcmp(winetest_platform, "wine")) dump++;
2145                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2146                                   context, count, expected->message, actual->message);
2147             }
2148         }
2149     }
2150     else
2151     {
2152         if (expected->message || actual->message)
2153         {
2154             dump++;
2155             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2156                               context, count, expected->message, actual->message);
2157         }
2158     }
2159     if( todo && !failcount) /* succeeded yet marked todo */
2160         todo_wine {
2161             if (!strcmp(winetest_platform, "wine")) dump++;
2162             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2163         }
2164
2165 done:
2166     if (dump) dump_sequence(expected_list, context, file, line);
2167     flush_sequence();
2168 }
2169
2170 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2171
2172 /******************************** MDI test **********************************/
2173
2174 /* CreateWindow for MDI frame window, initially visible */
2175 static const struct message WmCreateMDIframeSeq[] = {
2176     { HCBT_CREATEWND, hook },
2177     { WM_GETMINMAXINFO, sent },
2178     { WM_NCCREATE, sent },
2179     { WM_NCCALCSIZE, sent|wparam, 0 },
2180     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2181     { WM_CREATE, sent },
2182     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2183     { WM_NOTIFYFORMAT, sent|optional },
2184     { WM_QUERYUISTATE, sent|optional },
2185     { WM_WINDOWPOSCHANGING, sent|optional },
2186     { WM_GETMINMAXINFO, sent|optional },
2187     { WM_NCCALCSIZE, sent|optional },
2188     { WM_WINDOWPOSCHANGED, sent|optional },
2189     { WM_SHOWWINDOW, sent|wparam, 1 },
2190     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2191     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2192     { HCBT_ACTIVATE, hook },
2193     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2194     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2195     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2196     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2197     { WM_NCACTIVATE, sent },
2198     { WM_GETTEXT, sent|defwinproc|optional },
2199     { WM_ACTIVATE, sent|wparam, 1 },
2200     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2201     { HCBT_SETFOCUS, hook },
2202     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2203     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2204     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2205     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2206     /* Win9x adds SWP_NOZORDER below */
2207     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2208     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2209     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2210     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2211     { WM_MOVE, sent },
2212     { 0 }
2213 };
2214 /* DestroyWindow for MDI frame window, initially visible */
2215 static const struct message WmDestroyMDIframeSeq[] = {
2216     { HCBT_DESTROYWND, hook },
2217     { 0x0090, sent|optional },
2218     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2219     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2220     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2221     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2222     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2223     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2224     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2225     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2226     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2227     { WM_DESTROY, sent },
2228     { WM_NCDESTROY, sent },
2229     { 0 }
2230 };
2231 /* CreateWindow for MDI client window, initially visible */
2232 static const struct message WmCreateMDIclientSeq[] = {
2233     { HCBT_CREATEWND, hook },
2234     { WM_NCCREATE, sent },
2235     { WM_NCCALCSIZE, sent|wparam, 0 },
2236     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2237     { WM_CREATE, sent },
2238     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2239     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2240     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2241     { WM_MOVE, sent },
2242     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2243     { WM_SHOWWINDOW, sent|wparam, 1 },
2244     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2245     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2246     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2247     { 0 }
2248 };
2249 /* ShowWindow(SW_SHOW) for MDI client window */
2250 static const struct message WmShowMDIclientSeq[] = {
2251     { WM_SHOWWINDOW, sent|wparam, 1 },
2252     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2253     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2254     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2255     { 0 }
2256 };
2257 /* ShowWindow(SW_HIDE) for MDI client window */
2258 static const struct message WmHideMDIclientSeq[] = {
2259     { WM_SHOWWINDOW, sent|wparam, 0 },
2260     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2261     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2262     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2263     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2264     { 0 }
2265 };
2266 /* DestroyWindow for MDI client window, initially visible */
2267 static const struct message WmDestroyMDIclientSeq[] = {
2268     { HCBT_DESTROYWND, hook },
2269     { 0x0090, sent|optional },
2270     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2271     { WM_SHOWWINDOW, sent|wparam, 0 },
2272     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2273     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2274     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2275     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2276     { WM_DESTROY, sent },
2277     { WM_NCDESTROY, sent },
2278     { 0 }
2279 };
2280 /* CreateWindow for MDI child window, initially visible */
2281 static const struct message WmCreateMDIchildVisibleSeq[] = {
2282     { HCBT_CREATEWND, hook },
2283     { WM_NCCREATE, sent }, 
2284     { WM_NCCALCSIZE, sent|wparam, 0 },
2285     { WM_CREATE, sent },
2286     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2287     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2288     { WM_MOVE, sent },
2289     /* Win2k sends wparam set to
2290      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2291      * while Win9x doesn't bother to set child window id according to
2292      * CLIENTCREATESTRUCT.idFirstChild
2293      */
2294     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2295     { WM_SHOWWINDOW, sent|wparam, 1 },
2296     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2297     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2298     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2299     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2300     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2301     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2302     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2303
2304     /* Win9x: message sequence terminates here. */
2305
2306     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2307     { HCBT_SETFOCUS, hook }, /* in MDI client */
2308     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2309     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2310     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2311     { WM_SETFOCUS, sent }, /* in MDI client */
2312     { HCBT_SETFOCUS, hook },
2313     { WM_KILLFOCUS, sent }, /* in MDI client */
2314     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2315     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2316     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2317     { WM_SETFOCUS, sent|defwinproc },
2318     { WM_MDIACTIVATE, sent|defwinproc },
2319     { 0 }
2320 };
2321 /* CreateWindow for MDI child window with invisible parent */
2322 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2323     { HCBT_CREATEWND, hook },
2324     { WM_GETMINMAXINFO, sent },
2325     { WM_NCCREATE, sent }, 
2326     { WM_NCCALCSIZE, sent|wparam, 0 },
2327     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2328     { WM_CREATE, sent },
2329     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2330     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2331     { WM_MOVE, sent },
2332     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2333     { WM_SHOWWINDOW, sent|wparam, 1 },
2334     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2335     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2336     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2337     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2338
2339     /* Win9x: message sequence terminates here. */
2340
2341     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2342     { HCBT_SETFOCUS, hook }, /* in MDI client */
2343     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2344     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2345     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2346     { WM_SETFOCUS, sent }, /* in MDI client */
2347     { HCBT_SETFOCUS, hook },
2348     { WM_KILLFOCUS, sent }, /* in MDI client */
2349     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2350     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2351     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2352     { WM_SETFOCUS, sent|defwinproc },
2353     { WM_MDIACTIVATE, sent|defwinproc },
2354     { 0 }
2355 };
2356 /* DestroyWindow for MDI child window, initially visible */
2357 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2358     { HCBT_DESTROYWND, hook },
2359     /* Win2k sends wparam set to
2360      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2361      * while Win9x doesn't bother to set child window id according to
2362      * CLIENTCREATESTRUCT.idFirstChild
2363      */
2364     { 0x0090, sent|optional },
2365     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2366     { WM_SHOWWINDOW, sent|wparam, 0 },
2367     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2368     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2369     { WM_ERASEBKGND, sent|parent|optional },
2370     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2371
2372     /* { WM_DESTROY, sent }
2373      * Win9x: message sequence terminates here.
2374      */
2375
2376     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2377     { WM_KILLFOCUS, sent },
2378     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2379     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2380     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2381     { WM_SETFOCUS, sent }, /* in MDI client */
2382
2383     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2384     { WM_KILLFOCUS, sent }, /* in MDI client */
2385     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2386     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2387     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2388     { WM_SETFOCUS, sent }, /* in MDI client */
2389
2390     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2391
2392     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2393     { WM_KILLFOCUS, sent },
2394     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2395     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2396     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2397     { WM_SETFOCUS, sent }, /* in MDI client */
2398
2399     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2400     { WM_KILLFOCUS, sent }, /* in MDI client */
2401     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2402     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2403     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2404     { WM_SETFOCUS, sent }, /* in MDI client */
2405
2406     { WM_DESTROY, sent },
2407
2408     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2409     { WM_KILLFOCUS, sent },
2410     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2411     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2412     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2413     { WM_SETFOCUS, sent }, /* in MDI client */
2414
2415     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2416     { WM_KILLFOCUS, sent }, /* in MDI client */
2417     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2418     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2419     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2420     { WM_SETFOCUS, sent }, /* in MDI client */
2421
2422     { WM_NCDESTROY, sent },
2423     { 0 }
2424 };
2425 /* CreateWindow for MDI child window, initially invisible */
2426 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2427     { HCBT_CREATEWND, hook },
2428     { WM_NCCREATE, sent }, 
2429     { WM_NCCALCSIZE, sent|wparam, 0 },
2430     { WM_CREATE, sent },
2431     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2432     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2433     { WM_MOVE, sent },
2434     /* Win2k sends wparam set to
2435      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2436      * while Win9x doesn't bother to set child window id according to
2437      * CLIENTCREATESTRUCT.idFirstChild
2438      */
2439     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2440     { 0 }
2441 };
2442 /* DestroyWindow for MDI child window, initially invisible */
2443 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2444     { HCBT_DESTROYWND, hook },
2445     /* Win2k sends wparam set to
2446      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2447      * while Win9x doesn't bother to set child window id according to
2448      * CLIENTCREATESTRUCT.idFirstChild
2449      */
2450     { 0x0090, sent|optional },
2451     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2452     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2453     { WM_DESTROY, sent },
2454     { WM_NCDESTROY, sent },
2455     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2456     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2457     { 0 }
2458 };
2459 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2460 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2461     { HCBT_CREATEWND, hook },
2462     { WM_NCCREATE, sent }, 
2463     { WM_NCCALCSIZE, sent|wparam, 0 },
2464     { WM_CREATE, sent },
2465     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2466     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2467     { WM_MOVE, sent },
2468     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2469     { WM_GETMINMAXINFO, sent },
2470     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2471     { WM_NCCALCSIZE, sent|wparam, 1 },
2472     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2473     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2474      /* in MDI frame */
2475     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2476     { WM_NCCALCSIZE, sent|wparam, 1 },
2477     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2478     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2479     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2480     /* Win2k sends wparam set to
2481      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2482      * while Win9x doesn't bother to set child window id according to
2483      * CLIENTCREATESTRUCT.idFirstChild
2484      */
2485     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2486     { WM_SHOWWINDOW, sent|wparam, 1 },
2487     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2488     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2489     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2490     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2491     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2492     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2493     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2494
2495     /* Win9x: message sequence terminates here. */
2496
2497     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2498     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2499     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2500     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2501     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2502     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2503     { HCBT_SETFOCUS, hook|optional },
2504     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2505     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2506     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2507     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2508     { WM_SETFOCUS, sent|defwinproc|optional },
2509     { WM_MDIACTIVATE, sent|defwinproc|optional },
2510      /* in MDI frame */
2511     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2512     { WM_NCCALCSIZE, sent|wparam, 1 },
2513     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2514     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2515     { 0 }
2516 };
2517 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2518 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2519     /* restore the 1st MDI child */
2520     { WM_SETREDRAW, sent|wparam, 0 },
2521     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2522     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2523     { WM_NCCALCSIZE, sent|wparam, 1 },
2524     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2525     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2526     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2527      /* in MDI frame */
2528     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2529     { WM_NCCALCSIZE, sent|wparam, 1 },
2530     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2531     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2532     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2533     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2534     /* create the 2nd MDI child */
2535     { HCBT_CREATEWND, hook },
2536     { WM_NCCREATE, sent }, 
2537     { WM_NCCALCSIZE, sent|wparam, 0 },
2538     { WM_CREATE, sent },
2539     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2540     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2541     { WM_MOVE, sent },
2542     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2543     { WM_GETMINMAXINFO, sent },
2544     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2545     { WM_NCCALCSIZE, sent|wparam, 1 },
2546     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2547     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2548     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2549      /* in MDI frame */
2550     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2551     { WM_NCCALCSIZE, sent|wparam, 1 },
2552     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2553     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2554     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2555     /* Win2k sends wparam set to
2556      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2557      * while Win9x doesn't bother to set child window id according to
2558      * CLIENTCREATESTRUCT.idFirstChild
2559      */
2560     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2561     { WM_SHOWWINDOW, sent|wparam, 1 },
2562     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2563     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2564     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2565     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2566     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2567     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2568
2569     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2570     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2571
2572     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2573
2574     /* Win9x: message sequence terminates here. */
2575
2576     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2577     { HCBT_SETFOCUS, hook },
2578     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2579     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2580     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2581     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2582     { WM_SETFOCUS, sent }, /* in MDI client */
2583     { HCBT_SETFOCUS, hook },
2584     { WM_KILLFOCUS, sent }, /* in MDI client */
2585     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2586     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2587     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2588     { WM_SETFOCUS, sent|defwinproc },
2589
2590     { WM_MDIACTIVATE, sent|defwinproc },
2591      /* in MDI frame */
2592     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2593     { WM_NCCALCSIZE, sent|wparam, 1 },
2594     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2595     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2596     { 0 }
2597 };
2598 /* WM_MDICREATE MDI child window, initially visible and maximized */
2599 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2600     { WM_MDICREATE, sent },
2601     { HCBT_CREATEWND, hook },
2602     { WM_NCCREATE, sent }, 
2603     { WM_NCCALCSIZE, sent|wparam, 0 },
2604     { WM_CREATE, sent },
2605     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2606     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2607     { WM_MOVE, sent },
2608     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2609     { WM_GETMINMAXINFO, sent },
2610     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2611     { WM_NCCALCSIZE, sent|wparam, 1 },
2612     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2613     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2614
2615      /* in MDI frame */
2616     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2617     { WM_NCCALCSIZE, sent|wparam, 1 },
2618     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2619     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2620     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2621
2622     /* Win2k sends wparam set to
2623      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2624      * while Win9x doesn't bother to set child window id according to
2625      * CLIENTCREATESTRUCT.idFirstChild
2626      */
2627     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2628     { WM_SHOWWINDOW, sent|wparam, 1 },
2629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2630
2631     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2632
2633     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2634     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2635     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2636
2637     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2638     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2639
2640     /* Win9x: message sequence terminates here. */
2641
2642     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2643     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2644     { HCBT_SETFOCUS, hook }, /* in MDI client */
2645     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2646     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2647     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2648     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2649     { HCBT_SETFOCUS, hook|optional },
2650     { WM_KILLFOCUS, sent }, /* in MDI client */
2651     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2652     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2653     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2654     { WM_SETFOCUS, sent|defwinproc },
2655
2656     { WM_MDIACTIVATE, sent|defwinproc },
2657
2658      /* in MDI child */
2659     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2660     { WM_NCCALCSIZE, sent|wparam, 1 },
2661     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2662     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2663
2664      /* in MDI frame */
2665     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2666     { WM_NCCALCSIZE, sent|wparam, 1 },
2667     { 0x0093, sent|defwinproc|optional },
2668     { 0x0093, sent|defwinproc|optional },
2669     { 0x0093, sent|defwinproc|optional },
2670     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2671     { WM_MOVE, sent|defwinproc },
2672     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2673
2674      /* in MDI client */
2675     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2676     { WM_NCCALCSIZE, sent|wparam, 1 },
2677     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2678     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2679
2680      /* in MDI child */
2681     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2682     { WM_NCCALCSIZE, sent|wparam, 1 },
2683     { 0x0093, sent|optional },
2684     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2685     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2686
2687     { 0x0093, sent|optional },
2688     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2689     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2690     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2691     { 0x0093, sent|defwinproc|optional },
2692     { 0x0093, sent|defwinproc|optional },
2693     { 0x0093, sent|defwinproc|optional },
2694     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2695     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2696
2697     { 0 }
2698 };
2699 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2700 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2701     { HCBT_CREATEWND, hook },
2702     { WM_GETMINMAXINFO, sent },
2703     { WM_NCCREATE, sent }, 
2704     { WM_NCCALCSIZE, sent|wparam, 0 },
2705     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2706     { WM_CREATE, sent },
2707     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2708     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2709     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2710     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2711     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2712     { WM_MOVE, sent },
2713     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2714     { WM_GETMINMAXINFO, sent },
2715     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2716     { WM_GETMINMAXINFO, sent|defwinproc },
2717     { WM_NCCALCSIZE, sent|wparam, 1 },
2718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2719     { WM_MOVE, sent|defwinproc },
2720     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2721      /* in MDI frame */
2722     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2723     { WM_NCCALCSIZE, sent|wparam, 1 },
2724     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2725     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2726     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2727     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2728     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2729     /* Win2k sends wparam set to
2730      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2731      * while Win9x doesn't bother to set child window id according to
2732      * CLIENTCREATESTRUCT.idFirstChild
2733      */
2734     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2735     { 0 }
2736 };
2737 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2738 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2739     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2740     { HCBT_SYSCOMMAND, hook },
2741     { WM_CLOSE, sent|defwinproc },
2742     { WM_MDIDESTROY, sent }, /* in MDI client */
2743
2744     /* bring the 1st MDI child to top */
2745     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2746     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2747
2748     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2749
2750     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2751     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2752     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2753
2754     /* maximize the 1st MDI child */
2755     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2756     { WM_GETMINMAXINFO, sent|defwinproc },
2757     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2758     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2759     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2760     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2761     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2762
2763     /* restore the 2nd MDI child */
2764     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2765     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2766     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2767     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2768
2769     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2770
2771     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2772     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2773
2774     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2775
2776     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2777      /* in MDI frame */
2778     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2779     { WM_NCCALCSIZE, sent|wparam, 1 },
2780     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2781     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2782     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2783
2784     /* bring the 1st MDI child to top */
2785     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2786     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2787     { HCBT_SETFOCUS, hook },
2788     { WM_KILLFOCUS, sent|defwinproc },
2789     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2790     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2791     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2792     { WM_SETFOCUS, sent }, /* in MDI client */
2793     { HCBT_SETFOCUS, hook },
2794     { WM_KILLFOCUS, sent }, /* in MDI client */
2795     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2796     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2797     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2798     { WM_SETFOCUS, sent|defwinproc },
2799     { WM_MDIACTIVATE, sent|defwinproc },
2800     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2801
2802     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2803     { WM_SHOWWINDOW, sent|wparam, 1 },
2804     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2805     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2806     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2807     { WM_MDIREFRESHMENU, sent },
2808
2809     { HCBT_DESTROYWND, hook },
2810     /* Win2k sends wparam set to
2811      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2812      * while Win9x doesn't bother to set child window id according to
2813      * CLIENTCREATESTRUCT.idFirstChild
2814      */
2815     { 0x0090, sent|defwinproc|optional },
2816     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2817     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2818     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2819     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2820     { WM_ERASEBKGND, sent|parent|optional },
2821     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2822
2823     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2824     { WM_DESTROY, sent|defwinproc },
2825     { WM_NCDESTROY, sent|defwinproc },
2826     { 0 }
2827 };
2828 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2829 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2830     { WM_MDIDESTROY, sent }, /* in MDI client */
2831     { WM_SHOWWINDOW, sent|wparam, 0 },
2832     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2833     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2834     { WM_ERASEBKGND, sent|parent|optional },
2835     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2836
2837     { HCBT_SETFOCUS, hook },
2838     { WM_KILLFOCUS, sent },
2839     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2840     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2841     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2842     { WM_SETFOCUS, sent }, /* in MDI client */
2843     { HCBT_SETFOCUS, hook },
2844     { WM_KILLFOCUS, sent }, /* in MDI client */
2845     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2846     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2847     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2848     { WM_SETFOCUS, sent },
2849
2850      /* in MDI child */
2851     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2852     { WM_NCCALCSIZE, sent|wparam, 1 },
2853     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2854     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2855
2856      /* in MDI frame */
2857     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2858     { WM_NCCALCSIZE, sent|wparam, 1 },
2859     { 0x0093, sent|defwinproc|optional },
2860     { 0x0093, sent|defwinproc|optional },
2861     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2862     { WM_MOVE, sent|defwinproc },
2863     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2864
2865      /* in MDI client */
2866     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2867     { WM_NCCALCSIZE, sent|wparam, 1 },
2868     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2869     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2870
2871      /* in MDI child */
2872     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2873     { WM_NCCALCSIZE, sent|wparam, 1 },
2874     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2875     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2876
2877      /* in MDI child */
2878     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2879     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2880     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2881     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2882
2883      /* in MDI frame */
2884     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2885     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2886     { 0x0093, sent|defwinproc|optional },
2887     { 0x0093, sent|defwinproc|optional },
2888     { 0x0093, sent|defwinproc|optional },
2889     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2890     { WM_MOVE, sent|defwinproc },
2891     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2892
2893      /* in MDI client */
2894     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2895     { WM_NCCALCSIZE, sent|wparam, 1 },
2896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2897     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2898
2899      /* in MDI child */
2900     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2901     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2902     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2903     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2904     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2905     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2906
2907     { 0x0093, sent|defwinproc|optional },
2908     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2909     { 0x0093, sent|defwinproc|optional },
2910     { 0x0093, sent|defwinproc|optional },
2911     { 0x0093, sent|defwinproc|optional },
2912     { 0x0093, sent|optional },
2913
2914     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2915     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2916     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2917     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2918     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2919
2920      /* in MDI frame */
2921     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2922     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2923     { 0x0093, sent|defwinproc|optional },
2924     { 0x0093, sent|defwinproc|optional },
2925     { 0x0093, sent|defwinproc|optional },
2926     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2927     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2928     { 0x0093, sent|optional },
2929
2930     { WM_NCACTIVATE, sent|wparam, 0 },
2931     { WM_MDIACTIVATE, sent },
2932
2933     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2934     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2935     { WM_NCCALCSIZE, sent|wparam, 1 },
2936
2937     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2938
2939     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2940     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2941     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2942
2943      /* in MDI child */
2944     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2945     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2946     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2947     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2948
2949      /* in MDI frame */
2950     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2951     { WM_NCCALCSIZE, sent|wparam, 1 },
2952     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2953     { WM_MOVE, sent|defwinproc },
2954     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2955
2956      /* in MDI client */
2957     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2958     { WM_NCCALCSIZE, sent|wparam, 1 },
2959     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2960     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2961     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2962     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2963     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2964     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2965     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2966
2967     { HCBT_SETFOCUS, hook },
2968     { WM_KILLFOCUS, sent },
2969     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2970     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2971     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2972     { WM_SETFOCUS, sent }, /* in MDI client */
2973
2974     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2975
2976     { HCBT_DESTROYWND, hook },
2977     /* Win2k sends wparam set to
2978      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2979      * while Win9x doesn't bother to set child window id according to
2980      * CLIENTCREATESTRUCT.idFirstChild
2981      */
2982     { 0x0090, sent|optional },
2983     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2984
2985     { WM_SHOWWINDOW, sent|wparam, 0 },
2986     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2987     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2988     { WM_ERASEBKGND, sent|parent|optional },
2989     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2990
2991     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2992     { WM_DESTROY, sent },
2993     { WM_NCDESTROY, sent },
2994     { 0 }
2995 };
2996 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2997 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2998     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2999     { WM_GETMINMAXINFO, sent },
3000     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3001     { WM_NCCALCSIZE, sent|wparam, 1 },
3002     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3003     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3004
3005     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3006     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3007     { HCBT_SETFOCUS, hook|optional },
3008     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3009     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3010     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3011     { HCBT_SETFOCUS, hook|optional },
3012     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3013     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3014     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3015     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3016     { WM_SETFOCUS, sent|optional|defwinproc },
3017     { WM_MDIACTIVATE, sent|optional|defwinproc },
3018     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3019     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3020      /* in MDI frame */
3021     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3022     { WM_NCCALCSIZE, sent|wparam, 1 },
3023     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3024     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3025     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3026     { 0 }
3027 };
3028 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3029 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3030     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3031     { WM_GETMINMAXINFO, sent },
3032     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3033     { WM_GETMINMAXINFO, sent|defwinproc },
3034     { WM_NCCALCSIZE, sent|wparam, 1 },
3035     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3036     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3037
3038     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3039     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3040     { HCBT_SETFOCUS, hook|optional },
3041     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3042     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3043     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3044     { HCBT_SETFOCUS, hook|optional },
3045     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3046     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3047     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3048     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3049     { WM_SETFOCUS, sent|defwinproc|optional },
3050     { WM_MDIACTIVATE, sent|defwinproc|optional },
3051     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3052     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3053     { 0 }
3054 };
3055 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3056 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3057     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3058     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3059     { WM_GETMINMAXINFO, sent },
3060     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3061     { WM_GETMINMAXINFO, sent|defwinproc },
3062     { WM_NCCALCSIZE, sent|wparam, 1 },
3063     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3064     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3065     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3066     { WM_MOVE, sent|defwinproc },
3067     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3068
3069     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3070     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3071     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3072     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3073     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3074     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3075      /* in MDI frame */
3076     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3077     { WM_NCCALCSIZE, sent|wparam, 1 },
3078     { 0x0093, sent|defwinproc|optional },
3079     { 0x0094, sent|defwinproc|optional },
3080     { 0x0094, sent|defwinproc|optional },
3081     { 0x0094, sent|defwinproc|optional },
3082     { 0x0094, sent|defwinproc|optional },
3083     { 0x0093, sent|defwinproc|optional },
3084     { 0x0093, sent|defwinproc|optional },
3085     { 0x0091, sent|defwinproc|optional },
3086     { 0x0092, sent|defwinproc|optional },
3087     { 0x0092, sent|defwinproc|optional },
3088     { 0x0092, sent|defwinproc|optional },
3089     { 0x0092, sent|defwinproc|optional },
3090     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3091     { WM_MOVE, sent|defwinproc },
3092     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3093     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3094      /* in MDI client */
3095     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3096     { WM_NCCALCSIZE, sent|wparam, 1 },
3097     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3098     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3099      /* in MDI child */
3100     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3101     { WM_GETMINMAXINFO, sent|defwinproc },
3102     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3103     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3104     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3105     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3106     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3107     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3108     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3109     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3110      /* in MDI frame */
3111     { 0x0093, sent|optional },
3112     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3113     { 0x0093, sent|defwinproc|optional },
3114     { 0x0093, sent|defwinproc|optional },
3115     { 0x0093, sent|defwinproc|optional },
3116     { 0x0091, sent|defwinproc|optional },
3117     { 0x0092, sent|defwinproc|optional },
3118     { 0x0092, sent|defwinproc|optional },
3119     { 0x0092, sent|defwinproc|optional },
3120     { 0x0092, sent|defwinproc|optional },
3121     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3122     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3123     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3124     { 0 }
3125 };
3126 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3127 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3128     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3129     { WM_GETMINMAXINFO, sent },
3130     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3131     { WM_NCCALCSIZE, sent|wparam, 1 },
3132     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3133     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3134     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3135      /* in MDI frame */
3136     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3137     { WM_NCCALCSIZE, sent|wparam, 1 },
3138     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3139     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3140     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3141     { 0 }
3142 };
3143 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3144 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3145     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3146     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3147     { WM_NCCALCSIZE, sent|wparam, 1 },
3148     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3150     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3151      /* in MDI frame */
3152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3153     { WM_NCCALCSIZE, sent|wparam, 1 },
3154     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3155     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3156     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3157     { 0 }
3158 };
3159 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3160 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3161     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3162     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3163     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3164     { WM_NCCALCSIZE, sent|wparam, 1 },
3165     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3166     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3167     { WM_MOVE, sent|defwinproc },
3168     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3169     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3170     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3171     { HCBT_SETFOCUS, hook },
3172     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3173     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3174     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3175     { WM_SETFOCUS, sent },
3176     { 0 }
3177 };
3178 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3179 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3180     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3181     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3182     { WM_NCCALCSIZE, sent|wparam, 1 },
3183     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3184     { WM_MOVE, sent|defwinproc },
3185     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
3186     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3187     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3188     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3189     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3190     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3191     { 0 }
3192 };
3193 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3194 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3195     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3197     { WM_NCCALCSIZE, sent|wparam, 1 },
3198     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3199     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3200     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3201     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3202      /* in MDI frame */
3203     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3204     { WM_NCCALCSIZE, sent|wparam, 1 },
3205     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3206     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3207     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3208     { 0 }
3209 };
3210
3211 static HWND mdi_client;
3212 static WNDPROC old_mdi_client_proc;
3213
3214 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3215 {
3216     struct recvd_message msg;
3217
3218     /* do not log painting messages */
3219     if (message != WM_PAINT &&
3220         message != WM_NCPAINT &&
3221         message != WM_SYNCPAINT &&
3222         message != WM_ERASEBKGND &&
3223         message != WM_NCHITTEST &&
3224         message != WM_GETTEXT &&
3225         message != WM_MDIGETACTIVE &&
3226         !ignore_message( message ))
3227     {
3228         msg.hwnd = hwnd;
3229         msg.message = message;
3230         msg.flags = sent|wparam|lparam;
3231         msg.wParam = wParam;
3232         msg.lParam = lParam;
3233         msg.descr = "mdi client";
3234         add_message(&msg);
3235     }
3236
3237     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3238 }
3239
3240 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3241 {
3242     static LONG defwndproc_counter = 0;
3243     LRESULT ret;
3244     struct recvd_message msg;
3245
3246     /* do not log painting messages */
3247     if (message != WM_PAINT &&
3248         message != WM_NCPAINT &&
3249         message != WM_SYNCPAINT &&
3250         message != WM_ERASEBKGND &&
3251         message != WM_NCHITTEST &&
3252         message != WM_GETTEXT &&
3253         !ignore_message( message ))
3254     {
3255         switch (message)
3256         {
3257             case WM_MDIACTIVATE:
3258             {
3259                 HWND active, client = GetParent(hwnd);
3260
3261                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3262
3263                 if (hwnd == (HWND)lParam) /* if we are being activated */
3264                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3265                 else
3266                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3267                 break;
3268             }
3269         }
3270
3271         msg.hwnd = hwnd;
3272         msg.message = message;
3273         msg.flags = sent|wparam|lparam;
3274         if (defwndproc_counter) msg.flags |= defwinproc;
3275         msg.wParam = wParam;
3276         msg.lParam = lParam;
3277         msg.descr = "mdi child";
3278         add_message(&msg);
3279     }
3280
3281     defwndproc_counter++;
3282     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3283     defwndproc_counter--;
3284
3285     return ret;
3286 }
3287
3288 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3289 {
3290     static LONG defwndproc_counter = 0;
3291     LRESULT ret;
3292     struct recvd_message msg;
3293
3294     /* do not log painting messages */
3295     if (message != WM_PAINT &&
3296         message != WM_NCPAINT &&
3297         message != WM_SYNCPAINT &&
3298         message != WM_ERASEBKGND &&
3299         message != WM_NCHITTEST &&
3300         message != WM_GETTEXT &&
3301         !ignore_message( message ))
3302     {
3303         msg.hwnd = hwnd;
3304         msg.message = message;
3305         msg.flags = sent|wparam|lparam;
3306         if (defwndproc_counter) msg.flags |= defwinproc;
3307         msg.wParam = wParam;
3308         msg.lParam = lParam;
3309         msg.descr = "mdi frame";
3310         add_message(&msg);
3311     }
3312
3313     defwndproc_counter++;
3314     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3315     defwndproc_counter--;
3316
3317     return ret;
3318 }
3319
3320 static BOOL mdi_RegisterWindowClasses(void)
3321 {
3322     WNDCLASSA cls;
3323
3324     cls.style = 0;
3325     cls.lpfnWndProc = mdi_frame_wnd_proc;
3326     cls.cbClsExtra = 0;
3327     cls.cbWndExtra = 0;
3328     cls.hInstance = GetModuleHandleA(0);
3329     cls.hIcon = 0;
3330     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3331     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3332     cls.lpszMenuName = NULL;
3333     cls.lpszClassName = "MDI_frame_class";
3334     if (!RegisterClassA(&cls)) return FALSE;
3335
3336     cls.lpfnWndProc = mdi_child_wnd_proc;
3337     cls.lpszClassName = "MDI_child_class";
3338     if (!RegisterClassA(&cls)) return FALSE;
3339
3340     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3341     old_mdi_client_proc = cls.lpfnWndProc;
3342     cls.hInstance = GetModuleHandleA(0);
3343     cls.lpfnWndProc = mdi_client_hook_proc;
3344     cls.lpszClassName = "MDI_client_class";
3345     if (!RegisterClassA(&cls)) assert(0);
3346
3347     return TRUE;
3348 }
3349
3350 static void test_mdi_messages(void)
3351 {
3352     MDICREATESTRUCTA mdi_cs;
3353     CLIENTCREATESTRUCT client_cs;
3354     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3355     BOOL zoomed;
3356     HMENU hMenu = CreateMenu();
3357
3358     assert(mdi_RegisterWindowClasses());
3359
3360     flush_sequence();
3361
3362     trace("creating MDI frame window\n");
3363     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3364                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3365                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3366                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3367                                 GetDesktopWindow(), hMenu,
3368                                 GetModuleHandleA(0), NULL);
3369     assert(mdi_frame);
3370     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3371
3372     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3373     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3374
3375     trace("creating MDI client window\n");
3376     client_cs.hWindowMenu = 0;
3377     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3378     mdi_client = CreateWindowExA(0, "MDI_client_class",
3379                                  NULL,
3380                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3381                                  0, 0, 0, 0,
3382                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3383     assert(mdi_client);
3384     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3385
3386     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3387     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3388
3389     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3390     ok(!active_child, "wrong active MDI child %p\n", active_child);
3391     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3392
3393     SetFocus(0);
3394     flush_sequence();
3395
3396     trace("creating invisible MDI child window\n");
3397     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3398                                 WS_CHILD,
3399                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3400                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3401     assert(mdi_child);
3402
3403     flush_sequence();
3404     ShowWindow(mdi_child, SW_SHOWNORMAL);
3405     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3406
3407     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3408     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3409
3410     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3411     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3412
3413     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3414     ok(!active_child, "wrong active MDI child %p\n", active_child);
3415     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3416
3417     ShowWindow(mdi_child, SW_HIDE);
3418     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3419     flush_sequence();
3420
3421     ShowWindow(mdi_child, SW_SHOW);
3422     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3423
3424     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3425     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3426
3427     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3428     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3429
3430     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3431     ok(!active_child, "wrong active MDI child %p\n", active_child);
3432     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3433
3434     DestroyWindow(mdi_child);
3435     flush_sequence();
3436
3437     trace("creating visible MDI child window\n");
3438     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3439                                 WS_CHILD | WS_VISIBLE,
3440                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3441                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3442     assert(mdi_child);
3443     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3444
3445     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3446     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3447
3448     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3449     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3450
3451     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3452     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3453     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3454     flush_sequence();
3455
3456     DestroyWindow(mdi_child);
3457     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3458
3459     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3460     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3461
3462     /* Win2k: MDI client still returns a just destroyed child as active
3463      * Win9x: MDI client returns 0
3464      */
3465     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3466     ok(active_child == mdi_child || /* win2k */
3467        !active_child, /* win9x */
3468        "wrong active MDI child %p\n", active_child);
3469     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3470
3471     flush_sequence();
3472
3473     trace("creating invisible MDI child window\n");
3474     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3475                                 WS_CHILD,
3476                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3477                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3478     assert(mdi_child2);
3479     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3480
3481     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3482     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3483
3484     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3485     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3486
3487     /* Win2k: MDI client still returns a just destroyed child as active
3488      * Win9x: MDI client returns mdi_child2
3489      */
3490     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3491     ok(active_child == mdi_child || /* win2k */
3492        active_child == mdi_child2, /* win9x */
3493        "wrong active MDI child %p\n", active_child);
3494     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3495     flush_sequence();
3496
3497     ShowWindow(mdi_child2, SW_MAXIMIZE);
3498     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3499
3500     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3501     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3502
3503     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3504     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3505     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3506     flush_sequence();
3507
3508     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3509     ok(GetFocus() == mdi_child2 || /* win2k */
3510        GetFocus() == 0, /* win9x */
3511        "wrong focus window %p\n", GetFocus());
3512
3513     SetFocus(0);
3514     flush_sequence();
3515
3516     ShowWindow(mdi_child2, SW_HIDE);
3517     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3518
3519     ShowWindow(mdi_child2, SW_RESTORE);
3520     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3521     flush_sequence();
3522
3523     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3524     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3525
3526     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3527     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3528     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3529     flush_sequence();
3530
3531     SetFocus(0);
3532     flush_sequence();
3533
3534     ShowWindow(mdi_child2, SW_HIDE);
3535     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3536
3537     ShowWindow(mdi_child2, SW_SHOW);
3538     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3539
3540     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3541     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3542
3543     ShowWindow(mdi_child2, SW_MAXIMIZE);
3544     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3545
3546     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3547     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3548
3549     ShowWindow(mdi_child2, SW_RESTORE);
3550     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3551
3552     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3553     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3554
3555     ShowWindow(mdi_child2, SW_MINIMIZE);
3556     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3557
3558     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3559     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3560
3561     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3562     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3563     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3564     flush_sequence();
3565
3566     ShowWindow(mdi_child2, SW_RESTORE);
3567     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3568
3569     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3570     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3571
3572     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3573     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3574     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3575     flush_sequence();
3576
3577     SetFocus(0);
3578     flush_sequence();
3579
3580     ShowWindow(mdi_child2, SW_HIDE);
3581     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3582
3583     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3584     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3585
3586     DestroyWindow(mdi_child2);
3587     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3588
3589     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3590     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3591
3592     /* test for maximized MDI children */
3593     trace("creating maximized visible MDI child window 1\n");
3594     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3595                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3596                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3597                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3598     assert(mdi_child);
3599     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3600     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3601
3602     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3603     ok(GetFocus() == mdi_child || /* win2k */
3604        GetFocus() == 0, /* win9x */
3605        "wrong focus window %p\n", GetFocus());
3606
3607     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3608     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3609     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3610     flush_sequence();
3611
3612     trace("creating maximized visible MDI child window 2\n");
3613     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3614                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3615                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3616                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3617     assert(mdi_child2);
3618     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3619     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3620     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3621
3622     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3623     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3624
3625     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3626     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3627     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3628     flush_sequence();
3629
3630     trace("destroying maximized visible MDI child window 2\n");
3631     DestroyWindow(mdi_child2);
3632     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3633
3634     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3635
3636     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3637     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3638
3639     /* Win2k: MDI client still returns a just destroyed child as active
3640      * Win9x: MDI client returns 0
3641      */
3642     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3643     ok(active_child == mdi_child2 || /* win2k */
3644        !active_child, /* win9x */
3645        "wrong active MDI child %p\n", active_child);
3646     flush_sequence();
3647
3648     ShowWindow(mdi_child, SW_MAXIMIZE);
3649     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3650     flush_sequence();
3651
3652     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3653     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3654
3655     trace("re-creating maximized visible MDI child window 2\n");
3656     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3657                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3658                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3659                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3660     assert(mdi_child2);
3661     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3662     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3663     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3664
3665     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3666     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3667
3668     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3669     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3670     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3671     flush_sequence();
3672
3673     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3674     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3675     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3676
3677     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3678     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3679     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3680
3681     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3682     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3683     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3684     flush_sequence();
3685
3686     DestroyWindow(mdi_child);
3687     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3688
3689     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3690     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3691
3692     /* Win2k: MDI client still returns a just destroyed child as active
3693      * Win9x: MDI client returns 0
3694      */
3695     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3696     ok(active_child == mdi_child || /* win2k */
3697        !active_child, /* win9x */
3698        "wrong active MDI child %p\n", active_child);
3699     flush_sequence();
3700
3701     trace("creating maximized invisible MDI child window\n");
3702     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3703                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3704                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3705                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3706     assert(mdi_child2);
3707     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3708     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3709     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3710     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3711
3712     /* Win2k: MDI client still returns a just destroyed child as active
3713      * Win9x: MDI client returns 0
3714      */
3715     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3716     ok(active_child == mdi_child || /* win2k */
3717        !active_child || active_child == mdi_child2, /* win9x */
3718        "wrong active MDI child %p\n", active_child);
3719     flush_sequence();
3720
3721     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3722     ShowWindow(mdi_child2, SW_MAXIMIZE);
3723     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3724     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3725     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3726     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3727
3728     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3729     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3730     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3731     flush_sequence();
3732
3733     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3734     flush_sequence();
3735
3736     /* end of test for maximized MDI children */
3737     SetFocus(0);
3738     flush_sequence();
3739     trace("creating maximized visible MDI child window 1(Switch test)\n");
3740     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3741                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3742                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3743                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3744     assert(mdi_child);
3745     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3746     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3747
3748     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3749     ok(GetFocus() == mdi_child || /* win2k */
3750        GetFocus() == 0, /* win9x */
3751        "wrong focus window %p(Switch test)\n", GetFocus());
3752
3753     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3754     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3755     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3756     flush_sequence();
3757
3758     trace("creating maximized visible MDI child window 2(Switch test)\n");
3759     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3760                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3761                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3762                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3763     assert(mdi_child2);
3764     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3765
3766     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3767     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3768
3769     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3770     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3771
3772     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3773     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3774     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3775     flush_sequence();
3776
3777     trace("Switch child window.\n");
3778     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3779     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3780     trace("end of test for switch maximized MDI children\n");
3781     flush_sequence();
3782
3783     /* Prepare for switching test of not maximized MDI children  */
3784     ShowWindow( mdi_child, SW_NORMAL );
3785     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3786     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3787     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3788     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3789     flush_sequence();
3790
3791     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3792     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3793     trace("end of test for switch not maximized MDI children\n");
3794     flush_sequence();
3795
3796     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3797     flush_sequence();
3798
3799     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3800     flush_sequence();
3801
3802     SetFocus(0);
3803     flush_sequence();
3804     /* end of tests for switch maximized/not maximized MDI children */
3805
3806     mdi_cs.szClass = "MDI_child_Class";
3807     mdi_cs.szTitle = "MDI child";
3808     mdi_cs.hOwner = GetModuleHandleA(0);
3809     mdi_cs.x = 0;
3810     mdi_cs.y = 0;
3811     mdi_cs.cx = CW_USEDEFAULT;
3812     mdi_cs.cy = CW_USEDEFAULT;
3813     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3814     mdi_cs.lParam = 0;
3815     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3816     ok(mdi_child != 0, "MDI child creation failed\n");
3817     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3818
3819     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3820
3821     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3822     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3823
3824     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3825     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3826     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3827
3828     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3829     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3830     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3831     flush_sequence();
3832
3833     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3834     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3835
3836     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3837     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3838     ok(!active_child, "wrong active MDI child %p\n", active_child);
3839
3840     SetFocus(0);
3841     flush_sequence();
3842
3843     DestroyWindow(mdi_client);
3844     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3845
3846     /* test maximization of MDI child with invisible parent */
3847     client_cs.hWindowMenu = 0;
3848     mdi_client = CreateWindow("MDI_client_class",
3849                                  NULL,
3850                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3851                                  0, 0, 660, 430,
3852                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3853     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3854
3855     ShowWindow(mdi_client, SW_HIDE);
3856     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3857
3858     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3859                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3860                                 0, 0, 650, 440,
3861                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3862     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3863
3864     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3865     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3866     zoomed = IsZoomed(mdi_child);
3867     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3868     
3869     ShowWindow(mdi_client, SW_SHOW);
3870     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3871
3872     DestroyWindow(mdi_child);
3873     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3874
3875     /* end of test for maximization of MDI child with invisible parent */
3876
3877     DestroyWindow(mdi_client);
3878     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3879
3880     DestroyWindow(mdi_frame);
3881     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3882 }
3883 /************************* End of MDI test **********************************/
3884
3885 static void test_WM_SETREDRAW(HWND hwnd)
3886 {
3887     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3888
3889     flush_events();
3890     flush_sequence();
3891
3892     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3893     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3894
3895     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3896     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3897
3898     flush_sequence();
3899     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3900     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3901
3902     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3903     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3904
3905     /* restore original WS_VISIBLE state */
3906     SetWindowLongA(hwnd, GWL_STYLE, style);
3907
3908     flush_events();
3909     flush_sequence();
3910 }
3911
3912 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3913 {
3914     struct recvd_message msg;
3915
3916     if (ignore_message( message )) return 0;
3917
3918     switch (message)
3919     {
3920         /* ignore */
3921         case WM_MOUSEMOVE:
3922         case WM_NCMOUSEMOVE:
3923         case WM_NCMOUSELEAVE:
3924         case WM_SETCURSOR:
3925             return 0;
3926         case WM_NCHITTEST:
3927             return HTCLIENT;
3928     }
3929
3930     msg.hwnd = hwnd;
3931     msg.message = message;
3932     msg.flags = sent|wparam|lparam;
3933     msg.wParam = wParam;
3934     msg.lParam = lParam;
3935     msg.descr = "dialog";
3936     add_message(&msg);
3937
3938     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3939     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3940     return 0;
3941 }
3942
3943 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3944 {
3945     DWORD style, exstyle;
3946     INT xmin, xmax;
3947     BOOL ret;
3948
3949     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3950     style = GetWindowLongA(hwnd, GWL_STYLE);
3951     /* do not be confused by WS_DLGFRAME set */
3952     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3953
3954     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3955     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3956
3957     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3958     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3959     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3960         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3961     else
3962         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3963
3964     style = GetWindowLongA(hwnd, GWL_STYLE);
3965     if (set) ok(style & set, "style %08x should be set\n", set);
3966     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3967
3968     /* a subsequent call should do nothing */
3969     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3970     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3971     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3972
3973     xmin = 0xdeadbeef;
3974     xmax = 0xdeadbeef;
3975     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3976     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3977     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3978     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3979     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3980 }
3981
3982 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3983 {
3984     DWORD style, exstyle;
3985     SCROLLINFO si;
3986     BOOL ret;
3987
3988     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3989     style = GetWindowLongA(hwnd, GWL_STYLE);
3990     /* do not be confused by WS_DLGFRAME set */
3991     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3992
3993     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3994     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3995
3996     si.cbSize = sizeof(si);
3997     si.fMask = SIF_RANGE;
3998     si.nMin = min;
3999     si.nMax = max;
4000     SetScrollInfo(hwnd, ctl, &si, TRUE);
4001     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4002         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4003     else
4004         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4005
4006     style = GetWindowLongA(hwnd, GWL_STYLE);
4007     if (set) ok(style & set, "style %08x should be set\n", set);
4008     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4009
4010     /* a subsequent call should do nothing */
4011     SetScrollInfo(hwnd, ctl, &si, TRUE);
4012     if (style & WS_HSCROLL)
4013         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4014     else if (style & WS_VSCROLL)
4015         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4016     else
4017         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4018
4019     si.fMask = SIF_PAGE;
4020     si.nPage = 5;
4021     SetScrollInfo(hwnd, ctl, &si, FALSE);
4022     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4023
4024     si.fMask = SIF_POS;
4025     si.nPos = max - 1;
4026     SetScrollInfo(hwnd, ctl, &si, FALSE);
4027     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4028
4029     si.fMask = SIF_RANGE;
4030     si.nMin = 0xdeadbeef;
4031     si.nMax = 0xdeadbeef;
4032     ret = GetScrollInfo(hwnd, ctl, &si);
4033     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4034     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4035     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4036     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4037 }
4038
4039 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4040 static void test_scroll_messages(HWND hwnd)
4041 {
4042     SCROLLINFO si;
4043     INT min, max;
4044     BOOL ret;
4045
4046     flush_events();
4047     flush_sequence();
4048
4049     min = 0xdeadbeef;
4050     max = 0xdeadbeef;
4051     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4052     ok( ret, "GetScrollRange error %d\n", GetLastError());
4053     if (sequence->message != WmGetScrollRangeSeq[0].message)
4054         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4055     /* values of min and max are undefined */
4056     flush_sequence();
4057
4058     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4059     ok( ret, "SetScrollRange error %d\n", GetLastError());
4060     if (sequence->message != WmSetScrollRangeSeq[0].message)
4061         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4062     flush_sequence();
4063
4064     min = 0xdeadbeef;
4065     max = 0xdeadbeef;
4066     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4067     ok( ret, "GetScrollRange error %d\n", GetLastError());
4068     if (sequence->message != WmGetScrollRangeSeq[0].message)
4069         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4070     /* values of min and max are undefined */
4071     flush_sequence();
4072
4073     si.cbSize = sizeof(si);
4074     si.fMask = SIF_RANGE;
4075     si.nMin = 20;
4076     si.nMax = 160;
4077     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4078     if (sequence->message != WmSetScrollRangeSeq[0].message)
4079         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4080     flush_sequence();
4081
4082     si.fMask = SIF_PAGE;
4083     si.nPage = 10;
4084     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4085     if (sequence->message != WmSetScrollRangeSeq[0].message)
4086         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4087     flush_sequence();
4088
4089     si.fMask = SIF_POS;
4090     si.nPos = 20;
4091     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4092     if (sequence->message != WmSetScrollRangeSeq[0].message)
4093         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4094     flush_sequence();
4095
4096     si.fMask = SIF_RANGE;
4097     si.nMin = 0xdeadbeef;
4098     si.nMax = 0xdeadbeef;
4099     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4100     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4101     if (sequence->message != WmGetScrollInfoSeq[0].message)
4102         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4103     /* values of min and max are undefined */
4104     flush_sequence();
4105
4106     /* set WS_HSCROLL */
4107     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4108     /* clear WS_HSCROLL */
4109     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4110
4111     /* set WS_HSCROLL */
4112     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4113     /* clear WS_HSCROLL */
4114     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4115
4116     /* set WS_VSCROLL */
4117     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4118     /* clear WS_VSCROLL */
4119     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4120
4121     /* set WS_VSCROLL */
4122     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4123     /* clear WS_VSCROLL */
4124     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4125 }
4126
4127 static void test_showwindow(void)
4128 {
4129     HWND hwnd, hchild;
4130     RECT rc;
4131
4132     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4133                            100, 100, 200, 200, 0, 0, 0, NULL);
4134     ok (hwnd != 0, "Failed to create overlapped window\n");
4135     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4136                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4137     ok (hchild != 0, "Failed to create child\n");
4138     flush_sequence();
4139
4140     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4141     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4142     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4143     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4144
4145     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4146     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4147     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4148     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4149     /* back to invisible */
4150     ShowWindow(hchild, SW_HIDE);
4151     ShowWindow(hwnd, SW_HIDE);
4152     flush_sequence();
4153     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4154     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4155     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4156     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4157     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4158     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4159     flush_sequence();
4160     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4161     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4162     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4163     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4164     ShowWindow( hwnd, SW_SHOW);
4165     flush_sequence();
4166     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4167     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4168     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4169
4170     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4171     ShowWindow( hchild, SW_HIDE);
4172     flush_sequence();
4173     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4174     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4175     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4176
4177     SetCapture(hchild);
4178     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4179     DestroyWindow(hchild);
4180     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4181
4182     DestroyWindow(hwnd);
4183     flush_sequence();
4184
4185     /* Popup windows */
4186     /* Test 1:
4187      * 1. Create invisible maximized popup window.
4188      * 2. Move and resize it.
4189      * 3. Show it maximized.
4190      */
4191     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4192     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4193                            100, 100, 200, 200, 0, 0, 0, NULL);
4194     ok (hwnd != 0, "Failed to create popup window\n");
4195     ok(IsZoomed(hwnd), "window should be maximized\n");
4196     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4197
4198     GetWindowRect(hwnd, &rc);
4199     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4200         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4201         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4202         rc.left, rc.top, rc.right, rc.bottom);
4203     /* Reset window's size & position */
4204     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4205     ok(IsZoomed(hwnd), "window should be maximized\n");
4206     flush_sequence();
4207
4208     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4209     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4210     ok(IsZoomed(hwnd), "window should be maximized\n");
4211     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4212
4213     GetWindowRect(hwnd, &rc);
4214     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4215         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4216         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4217         rc.left, rc.top, rc.right, rc.bottom);
4218     DestroyWindow(hwnd);
4219     flush_sequence();
4220
4221     /* Test 2:
4222      * 1. Create invisible maximized popup window.
4223      * 2. Show it maximized.
4224      */
4225     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4226     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4227                            100, 100, 200, 200, 0, 0, 0, NULL);
4228     ok (hwnd != 0, "Failed to create popup window\n");
4229     ok(IsZoomed(hwnd), "window should be maximized\n");
4230     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4231
4232     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4233     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4234     ok(IsZoomed(hwnd), "window should be maximized\n");
4235     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4236     DestroyWindow(hwnd);
4237     flush_sequence();
4238
4239     /* Test 3:
4240      * 1. Create visible maximized popup window.
4241      */
4242     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4243     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4244                            100, 100, 200, 200, 0, 0, 0, NULL);
4245     ok (hwnd != 0, "Failed to create popup window\n");
4246     ok(IsZoomed(hwnd), "window should be maximized\n");
4247     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4248     DestroyWindow(hwnd);
4249     flush_sequence();
4250
4251     /* Test 4:
4252      * 1. Create visible popup window.
4253      * 2. Maximize it.
4254      */
4255     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4256     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4257                            100, 100, 200, 200, 0, 0, 0, NULL);
4258     ok (hwnd != 0, "Failed to create popup window\n");
4259     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4260     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4261
4262     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4263     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4264     ok(IsZoomed(hwnd), "window should be maximized\n");
4265     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4266     DestroyWindow(hwnd);
4267     flush_sequence();
4268 }
4269
4270 static void test_sys_menu(void)
4271 {
4272     HWND hwnd;
4273     HMENU hmenu;
4274     UINT state;
4275
4276     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4277                            100, 100, 200, 200, 0, 0, 0, NULL);
4278     ok (hwnd != 0, "Failed to create overlapped window\n");
4279
4280     flush_sequence();
4281
4282     /* test existing window without CS_NOCLOSE style */
4283     hmenu = GetSystemMenu(hwnd, FALSE);
4284     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4285
4286     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4287     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4288     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4289
4290     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4291     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4292
4293     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4294     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4295     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4296
4297     EnableMenuItem(hmenu, SC_CLOSE, 0);
4298     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4299
4300     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4301     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4302     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4303
4304     /* test whether removing WS_SYSMENU destroys a system menu */
4305     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4306     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4307     flush_sequence();
4308     hmenu = GetSystemMenu(hwnd, FALSE);
4309     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4310
4311     DestroyWindow(hwnd);
4312
4313     /* test new window with CS_NOCLOSE style */
4314     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4315                            100, 100, 200, 200, 0, 0, 0, NULL);
4316     ok (hwnd != 0, "Failed to create overlapped window\n");
4317
4318     hmenu = GetSystemMenu(hwnd, FALSE);
4319     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4320
4321     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4322     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4323
4324     DestroyWindow(hwnd);
4325
4326     /* test new window without WS_SYSMENU style */
4327     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4328                            100, 100, 200, 200, 0, 0, 0, NULL);
4329     ok(hwnd != 0, "Failed to create overlapped window\n");
4330
4331     hmenu = GetSystemMenu(hwnd, FALSE);
4332     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4333
4334     DestroyWindow(hwnd);
4335 }
4336
4337 /* For shown WS_OVERLAPPEDWINDOW */
4338 static const struct message WmSetIcon_1[] = {
4339     { WM_SETICON, sent },
4340     { 0x00AE, sent|defwinproc|optional }, /* XP */
4341     { WM_GETTEXT, sent|defwinproc|optional },
4342     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4343     { 0 }
4344 };
4345
4346 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4347 static const struct message WmSetIcon_2[] = {
4348     { WM_SETICON, sent },
4349     { 0 }
4350 };
4351
4352 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4353 static const struct message WmInitEndSession[] = {
4354     { 0x003B, sent },
4355     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4356     { 0 }
4357 };
4358
4359 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4360 static const struct message WmInitEndSession_2[] = {
4361     { 0x003B, sent },
4362     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4363     { 0 }
4364 };
4365
4366 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4367 static const struct message WmInitEndSession_3[] = {
4368     { 0x003B, sent },
4369     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4370     { 0 }
4371 };
4372
4373 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4374 static const struct message WmInitEndSession_4[] = {
4375     { 0x003B, sent },
4376     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4377     { 0 }
4378 };
4379
4380 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4381 static const struct message WmInitEndSession_5[] = {
4382     { 0x003B, sent },
4383     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4384     { 0 }
4385 };
4386
4387 static const struct message WmOptionalPaint[] = {
4388     { WM_PAINT, sent|optional },
4389     { WM_NCPAINT, sent|beginpaint|optional },
4390     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4391     { WM_ERASEBKGND, sent|beginpaint|optional },
4392     { 0 }
4393 };
4394
4395 static const struct message WmZOrder[] = {
4396     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4397     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4398     { HCBT_ACTIVATE, hook },
4399     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4400     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4401     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4402     { WM_GETTEXT, sent|optional },
4403     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4404     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4405     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4406     { WM_GETTEXT, sent|defwinproc|optional },
4407     { WM_GETTEXT, sent|defwinproc|optional },
4408     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4409     { HCBT_SETFOCUS, hook },
4410     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4411     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4412     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4413     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4414     { WM_GETTEXT, sent|optional },
4415     { WM_NCCALCSIZE, sent|optional },
4416     { 0 }
4417 };
4418
4419 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4420 {
4421     DWORD ret;
4422     MSG msg;
4423
4424     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4425     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4426
4427     PostMessageA(hwnd, WM_USER, 0, 0);
4428
4429     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4430     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4431
4432     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4433     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4434
4435     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4436     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4437
4438     PostMessageA(hwnd, WM_USER, 0, 0);
4439
4440     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4441     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4442
4443     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4444     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4445
4446     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4447     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4448     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4449
4450     PostMessageA(hwnd, WM_USER, 0, 0);
4451
4452     /* new incoming message causes it to become signaled again */
4453     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4454     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4455
4456     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4457     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4458     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4459     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4460 }
4461
4462 /* test if we receive the right sequence of messages */
4463 static void test_messages(void)
4464 {
4465     HWND hwnd, hparent, hchild;
4466     HWND hchild2, hbutton;
4467     HMENU hmenu;
4468     MSG msg;
4469     LRESULT res;
4470
4471     flush_sequence();
4472
4473     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4474                            100, 100, 200, 200, 0, 0, 0, NULL);
4475     ok (hwnd != 0, "Failed to create overlapped window\n");
4476     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4477
4478     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4479     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4480     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4481
4482     /* test WM_SETREDRAW on a not visible top level window */
4483     test_WM_SETREDRAW(hwnd);
4484
4485     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4486     flush_events();
4487     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4488     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4489
4490     ok(GetActiveWindow() == hwnd, "window should be active\n");
4491     ok(GetFocus() == hwnd, "window should have input focus\n");
4492     ShowWindow(hwnd, SW_HIDE);
4493     flush_events();
4494     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4495
4496     ShowWindow(hwnd, SW_SHOW);
4497     flush_events();
4498     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4499
4500     ShowWindow(hwnd, SW_HIDE);
4501     flush_events();
4502     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4503
4504     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4505     flush_events();
4506     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4507     flush_sequence();
4508
4509     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4510     {
4511         ShowWindow(hwnd, SW_RESTORE);
4512         flush_events();
4513         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4514         flush_sequence();
4515     }
4516
4517     ShowWindow(hwnd, SW_MINIMIZE);
4518     flush_events();
4519     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4520     flush_sequence();
4521
4522     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4523     {
4524         ShowWindow(hwnd, SW_RESTORE);
4525         flush_events();
4526         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4527         flush_sequence();
4528     }
4529
4530     ShowWindow(hwnd, SW_SHOW);
4531     flush_events();
4532     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4533
4534     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4535     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4536     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4537     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4538
4539     /* test WM_SETREDRAW on a visible top level window */
4540     ShowWindow(hwnd, SW_SHOW);
4541     flush_events();
4542     test_WM_SETREDRAW(hwnd);
4543
4544     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4545     test_scroll_messages(hwnd);
4546
4547     /* test resizing and moving */
4548     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4549     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4550     flush_events();
4551     flush_sequence();
4552     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4553     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4554     flush_events();
4555     flush_sequence();
4556     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4557     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4558     flush_events();
4559     flush_sequence();
4560
4561     /* popups don't get WM_GETMINMAXINFO */
4562     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4563     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4564     flush_sequence();
4565     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4566     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4567
4568     DestroyWindow(hwnd);
4569     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4570
4571     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4572                               100, 100, 200, 200, 0, 0, 0, NULL);
4573     ok (hparent != 0, "Failed to create parent window\n");
4574     flush_sequence();
4575
4576     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4577                              0, 0, 10, 10, hparent, 0, 0, NULL);
4578     ok (hchild != 0, "Failed to create child window\n");
4579     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4580     DestroyWindow(hchild);
4581     flush_sequence();
4582
4583     /* visible child window with a caption */
4584     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4585                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4586                              0, 0, 10, 10, hparent, 0, 0, NULL);
4587     ok (hchild != 0, "Failed to create child window\n");
4588     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4589
4590     trace("testing scroll APIs on a visible child window %p\n", hchild);
4591     test_scroll_messages(hchild);
4592
4593     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4594     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4595
4596     DestroyWindow(hchild);
4597     flush_sequence();
4598
4599     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4600                              0, 0, 10, 10, hparent, 0, 0, NULL);
4601     ok (hchild != 0, "Failed to create child window\n");
4602     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4603     
4604     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4605                                100, 100, 50, 50, hparent, 0, 0, NULL);
4606     ok (hchild2 != 0, "Failed to create child2 window\n");
4607     flush_sequence();
4608
4609     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4610                               0, 100, 50, 50, hchild, 0, 0, NULL);
4611     ok (hbutton != 0, "Failed to create button window\n");
4612
4613     /* test WM_SETREDRAW on a not visible child window */
4614     test_WM_SETREDRAW(hchild);
4615
4616     ShowWindow(hchild, SW_SHOW);
4617     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4618
4619     /* check parent messages too */
4620     log_all_parent_messages++;
4621     ShowWindow(hchild, SW_HIDE);
4622     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4623     log_all_parent_messages--;
4624
4625     ShowWindow(hchild, SW_SHOW);
4626     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4627
4628     ShowWindow(hchild, SW_HIDE);
4629     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4630
4631     ShowWindow(hchild, SW_SHOW);
4632     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4633
4634     /* test WM_SETREDRAW on a visible child window */
4635     test_WM_SETREDRAW(hchild);
4636
4637     log_all_parent_messages++;
4638     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4639     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4640     log_all_parent_messages--;
4641
4642     ShowWindow(hchild, SW_HIDE);
4643     flush_sequence();
4644     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4645     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4646
4647     ShowWindow(hchild, SW_HIDE);
4648     flush_sequence();
4649     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4650     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4651
4652     /* DestroyWindow sequence below expects that a child has focus */
4653     SetFocus(hchild);
4654     flush_sequence();
4655
4656     DestroyWindow(hchild);
4657     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4658     DestroyWindow(hchild2);
4659     DestroyWindow(hbutton);
4660
4661     flush_sequence();
4662     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4663                              0, 0, 100, 100, hparent, 0, 0, NULL);
4664     ok (hchild != 0, "Failed to create child popup window\n");
4665     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4666     DestroyWindow(hchild);
4667
4668     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4669     flush_sequence();
4670     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4671                              0, 0, 100, 100, hparent, 0, 0, NULL);
4672     ok (hchild != 0, "Failed to create popup window\n");
4673     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4674     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4675     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4676     flush_sequence();
4677     ShowWindow(hchild, SW_SHOW);
4678     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4679     flush_sequence();
4680     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4681     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4682     flush_sequence();
4683     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4684     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4685     DestroyWindow(hchild);
4686
4687     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4688      * changes nothing in message sequences.
4689      */
4690     flush_sequence();
4691     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4692                              0, 0, 100, 100, hparent, 0, 0, NULL);
4693     ok (hchild != 0, "Failed to create popup window\n");
4694     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4695     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4696     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4697     flush_sequence();
4698     ShowWindow(hchild, SW_SHOW);
4699     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4700     flush_sequence();
4701     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4702     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4703     DestroyWindow(hchild);
4704
4705     flush_sequence();
4706     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4707                            0, 0, 100, 100, hparent, 0, 0, NULL);
4708     ok(hwnd != 0, "Failed to create custom dialog window\n");
4709     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4710
4711     /*
4712     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4713     test_scroll_messages(hwnd);
4714     */
4715
4716     flush_sequence();
4717
4718     test_def_id = 1;
4719     SendMessage(hwnd, WM_NULL, 0, 0);
4720
4721     flush_sequence();
4722     after_end_dialog = 1;
4723     EndDialog( hwnd, 0 );
4724     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4725
4726     DestroyWindow(hwnd);
4727     after_end_dialog = 0;
4728     test_def_id = 0;
4729
4730     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4731                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4732     ok(hwnd != 0, "Failed to create custom dialog window\n");
4733     flush_sequence();
4734     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4735     ShowWindow(hwnd, SW_SHOW);
4736     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4737     DestroyWindow(hwnd);
4738
4739     flush_sequence();
4740     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4741     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4742
4743     DestroyWindow(hparent);
4744     flush_sequence();
4745
4746     /* Message sequence for SetMenu */
4747     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4748     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4749
4750     hmenu = CreateMenu();
4751     ok (hmenu != 0, "Failed to create menu\n");
4752     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4753     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4754                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4755     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4756     ok (SetMenu(hwnd, 0), "SetMenu\n");
4757     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4758     ok (SetMenu(hwnd, 0), "SetMenu\n");
4759     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4760     ShowWindow(hwnd, SW_SHOW);
4761     UpdateWindow( hwnd );
4762     flush_events();
4763     flush_sequence();
4764     ok (SetMenu(hwnd, 0), "SetMenu\n");
4765     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4766     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4767     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4768
4769     UpdateWindow( hwnd );
4770     flush_events();
4771     flush_sequence();
4772     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4773     flush_events();
4774     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4775
4776     DestroyWindow(hwnd);
4777     flush_sequence();
4778
4779     /* Message sequence for EnableWindow */
4780     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4781                               100, 100, 200, 200, 0, 0, 0, NULL);
4782     ok (hparent != 0, "Failed to create parent window\n");
4783     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4784                              0, 0, 10, 10, hparent, 0, 0, NULL);
4785     ok (hchild != 0, "Failed to create child window\n");
4786
4787     SetFocus(hchild);
4788     flush_events();
4789     flush_sequence();
4790
4791     EnableWindow(hparent, FALSE);
4792     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4793
4794     EnableWindow(hparent, TRUE);
4795     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4796
4797     flush_events();
4798     flush_sequence();
4799
4800     test_MsgWaitForMultipleObjects(hparent);
4801
4802     /* the following test causes an exception in user.exe under win9x */
4803     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4804     {
4805         DestroyWindow(hparent);
4806         flush_sequence();
4807         return;
4808     }
4809     PostMessageW( hparent, WM_USER+1, 0, 0 );
4810     /* PeekMessage(NULL) fails, but still removes the message */
4811     SetLastError(0xdeadbeef);
4812     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4813     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4814         GetLastError() == 0xdeadbeef, /* NT4 */
4815         "last error is %d\n", GetLastError() );
4816     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4817     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4818
4819     DestroyWindow(hchild);
4820     DestroyWindow(hparent);
4821     flush_sequence();
4822
4823     /* Message sequences for WM_SETICON */
4824     trace("testing WM_SETICON\n");
4825     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4826                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4827                            NULL, NULL, 0);
4828     ShowWindow(hwnd, SW_SHOW);
4829     UpdateWindow(hwnd);
4830     flush_events();
4831     flush_sequence();
4832     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4833     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4834
4835     ShowWindow(hwnd, SW_HIDE);
4836     flush_events();
4837     flush_sequence();
4838     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4839     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4840     DestroyWindow(hwnd);
4841     flush_sequence();
4842
4843     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4844                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4845                            NULL, NULL, 0);
4846     ShowWindow(hwnd, SW_SHOW);
4847     UpdateWindow(hwnd);
4848     flush_events();
4849     flush_sequence();
4850     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4851     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4852
4853     ShowWindow(hwnd, SW_HIDE);
4854     flush_events();
4855     flush_sequence();
4856     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4857     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4858
4859     flush_sequence();
4860     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4861     if (!res)
4862     {
4863         todo_wine win_skip( "Message 0x3b not supported\n" );
4864         goto done;
4865     }
4866     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4867     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4868     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4869     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4870     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4871     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4872     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4873     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4874
4875     flush_sequence();
4876     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4877     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4878     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4879     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4880     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4881     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4882
4883     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4884     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4885     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4886
4887     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4888     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4889     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4890
4891 done:
4892     DestroyWindow(hwnd);
4893     flush_sequence();
4894 }
4895
4896 static void test_setwindowpos(void)
4897 {
4898     HWND hwnd;
4899     RECT rc;
4900     LRESULT res;
4901     const INT winX = 100;
4902     const INT winY = 100;
4903     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4904
4905     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4906                            0, 0, winX, winY, 0,
4907                            NULL, NULL, 0);
4908
4909     GetWindowRect(hwnd, &rc);
4910     expect(sysX, rc.right);
4911     expect(winY, rc.bottom);
4912
4913     flush_events();
4914     flush_sequence();
4915     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4916     ok_sequence(WmZOrder, "Z-Order", TRUE);
4917     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4918
4919     GetWindowRect(hwnd, &rc);
4920     expect(sysX, rc.right);
4921     expect(winY, rc.bottom);
4922     DestroyWindow(hwnd);
4923 }
4924
4925 static void invisible_parent_tests(void)
4926 {
4927     HWND hparent, hchild;
4928
4929     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4930                               100, 100, 200, 200, 0, 0, 0, NULL);
4931     ok (hparent != 0, "Failed to create parent window\n");
4932     flush_sequence();
4933
4934     /* test showing child with hidden parent */
4935
4936     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4937                              0, 0, 10, 10, hparent, 0, 0, NULL);
4938     ok (hchild != 0, "Failed to create child window\n");
4939     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4940
4941     ShowWindow( hchild, SW_MINIMIZE );
4942     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4943     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4944     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4945
4946     /* repeat */
4947     flush_events();
4948     flush_sequence();
4949     ShowWindow( hchild, SW_MINIMIZE );
4950     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4951
4952     DestroyWindow(hchild);
4953     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4954                              0, 0, 10, 10, hparent, 0, 0, NULL);
4955     flush_sequence();
4956
4957     ShowWindow( hchild, SW_MAXIMIZE );
4958     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4959     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4960     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4961
4962     /* repeat */
4963     flush_events();
4964     flush_sequence();
4965     ShowWindow( hchild, SW_MAXIMIZE );
4966     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4967
4968     DestroyWindow(hchild);
4969     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4970                              0, 0, 10, 10, hparent, 0, 0, NULL);
4971     flush_sequence();
4972
4973     ShowWindow( hchild, SW_RESTORE );
4974     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4975     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4976     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4977
4978     DestroyWindow(hchild);
4979     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4980                              0, 0, 10, 10, hparent, 0, 0, NULL);
4981     flush_sequence();
4982
4983     ShowWindow( hchild, SW_SHOWMINIMIZED );
4984     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4985     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4986     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4987
4988     /* repeat */
4989     flush_events();
4990     flush_sequence();
4991     ShowWindow( hchild, SW_SHOWMINIMIZED );
4992     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4993
4994     DestroyWindow(hchild);
4995     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4996                              0, 0, 10, 10, hparent, 0, 0, NULL);
4997     flush_sequence();
4998
4999     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5000     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5001     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5002     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5003     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5004
5005     DestroyWindow(hchild);
5006     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5007                              0, 0, 10, 10, hparent, 0, 0, NULL);
5008     flush_sequence();
5009
5010     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5011     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5012     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5013     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5014
5015     /* repeat */
5016     flush_events();
5017     flush_sequence();
5018     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5019     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5020
5021     DestroyWindow(hchild);
5022     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5023                              0, 0, 10, 10, hparent, 0, 0, NULL);
5024     flush_sequence();
5025
5026     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5027     ShowWindow( hchild, SW_FORCEMINIMIZE );
5028     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5029 todo_wine {
5030     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5031 }
5032     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5033
5034     DestroyWindow(hchild);
5035     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5036                              0, 0, 10, 10, hparent, 0, 0, NULL);
5037     flush_sequence();
5038
5039     ShowWindow( hchild, SW_SHOWNA );
5040     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5041     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5042     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5043
5044     /* repeat */
5045     flush_events();
5046     flush_sequence();
5047     ShowWindow( hchild, SW_SHOWNA );
5048     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5049
5050     DestroyWindow(hchild);
5051     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5052                              0, 0, 10, 10, hparent, 0, 0, NULL);
5053     flush_sequence();
5054
5055     ShowWindow( hchild, SW_SHOW );
5056     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5057     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5058     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5059
5060     /* repeat */
5061     flush_events();
5062     flush_sequence();
5063     ShowWindow( hchild, SW_SHOW );
5064     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5065
5066     ShowWindow( hchild, SW_HIDE );
5067     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5068     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5069     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5070
5071     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5072     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5073     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5074     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5075
5076     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5077     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5078     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5079     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5080
5081     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5082     flush_sequence();
5083     DestroyWindow(hchild);
5084     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5085
5086     DestroyWindow(hparent);
5087     flush_sequence();
5088 }
5089
5090 /****************** button message test *************************/
5091 static const struct message WmSetFocusButtonSeq[] =
5092 {
5093     { HCBT_SETFOCUS, hook },
5094     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5095     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5096     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5097     { WM_SETFOCUS, sent|wparam, 0 },
5098     { WM_CTLCOLORBTN, sent|defwinproc },
5099     { 0 }
5100 };
5101 static const struct message WmKillFocusButtonSeq[] =
5102 {
5103     { HCBT_SETFOCUS, hook },
5104     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5105     { WM_KILLFOCUS, sent|wparam, 0 },
5106     { WM_CTLCOLORBTN, sent|defwinproc },
5107     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5108     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5109     { 0 }
5110 };
5111 static const struct message WmSetFocusStaticSeq[] =
5112 {
5113     { HCBT_SETFOCUS, hook },
5114     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5115     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5116     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5117     { WM_SETFOCUS, sent|wparam, 0 },
5118     { WM_CTLCOLORSTATIC, sent|defwinproc },
5119     { 0 }
5120 };
5121 static const struct message WmKillFocusStaticSeq[] =
5122 {
5123     { HCBT_SETFOCUS, hook },
5124     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5125     { WM_KILLFOCUS, sent|wparam, 0 },
5126     { WM_CTLCOLORSTATIC, sent|defwinproc },
5127     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5128     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5129     { 0 }
5130 };
5131 static const struct message WmLButtonDownSeq[] =
5132 {
5133     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5134     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5135     { HCBT_SETFOCUS, hook },
5136     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5137     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5138     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5139     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5140     { WM_CTLCOLORBTN, sent|defwinproc },
5141     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5142     { WM_CTLCOLORBTN, sent|defwinproc },
5143     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5144     { 0 }
5145 };
5146 static const struct message WmLButtonUpSeq[] =
5147 {
5148     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5149     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5150     { WM_CTLCOLORBTN, sent|defwinproc },
5151     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5152     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5153     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5154     { 0 }
5155 };
5156 static const struct message WmSetFontButtonSeq[] =
5157 {
5158     { WM_SETFONT, sent },
5159     { WM_PAINT, sent },
5160     { WM_ERASEBKGND, sent|defwinproc|optional },
5161     { WM_CTLCOLORBTN, sent|defwinproc },
5162     { 0 }
5163 };
5164
5165 static WNDPROC old_button_proc;
5166
5167 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5168 {
5169     static long defwndproc_counter = 0;
5170     LRESULT ret;
5171     struct recvd_message msg;
5172
5173     if (ignore_message( message )) return 0;
5174
5175     switch (message)
5176     {
5177     case WM_SYNCPAINT:
5178         break;
5179     case BM_SETSTATE:
5180         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5181         /* fall through */
5182     default:
5183         msg.hwnd = hwnd;
5184         msg.message = message;
5185         msg.flags = sent|wparam|lparam;
5186         if (defwndproc_counter) msg.flags |= defwinproc;
5187         msg.wParam = wParam;
5188         msg.lParam = lParam;
5189         msg.descr = "button";
5190         add_message(&msg);
5191     }
5192
5193     defwndproc_counter++;
5194     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5195     defwndproc_counter--;
5196
5197     return ret;
5198 }
5199
5200 static void subclass_button(void)
5201 {
5202     WNDCLASSA cls;
5203
5204     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5205
5206     old_button_proc = cls.lpfnWndProc;
5207
5208     cls.hInstance = GetModuleHandle(0);
5209     cls.lpfnWndProc = button_hook_proc;
5210     cls.lpszClassName = "my_button_class";
5211     UnregisterClass(cls.lpszClassName, cls.hInstance);
5212     if (!RegisterClassA(&cls)) assert(0);
5213 }
5214
5215 static void test_button_messages(void)
5216 {
5217     static const struct
5218     {
5219         DWORD style;
5220         DWORD dlg_code;
5221         const struct message *setfocus;
5222         const struct message *killfocus;
5223     } button[] = {
5224         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5225           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5226         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5227           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5228         { BS_CHECKBOX, DLGC_BUTTON,
5229           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5230         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5231           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5232         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5233           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5234         { BS_3STATE, DLGC_BUTTON,
5235           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5236         { BS_AUTO3STATE, DLGC_BUTTON,
5237           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5238         { BS_GROUPBOX, DLGC_STATIC,
5239           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5240         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5241           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5242         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5243           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5244         { BS_OWNERDRAW, DLGC_BUTTON,
5245           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
5246     };
5247     unsigned int i;
5248     HWND hwnd;
5249     DWORD dlg_code;
5250     HFONT zfont;
5251
5252     /* selection with VK_SPACE should capture button window */
5253     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5254                            0, 0, 50, 14, 0, 0, 0, NULL);
5255     ok(hwnd != 0, "Failed to create button window\n");
5256     ReleaseCapture();
5257     SetFocus(hwnd);
5258     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5259     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5260     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5261     DestroyWindow(hwnd);
5262
5263     subclass_button();
5264
5265     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5266     {
5267         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
5268                                0, 0, 50, 14, 0, 0, 0, NULL);
5269         ok(hwnd != 0, "Failed to create button window\n");
5270
5271         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5272         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5273
5274         ShowWindow(hwnd, SW_SHOW);
5275         UpdateWindow(hwnd);
5276         SetFocus(0);
5277         flush_sequence();
5278
5279         trace("button style %08x\n", button[i].style);
5280         SetFocus(hwnd);
5281         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5282
5283         SetFocus(0);
5284         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5285
5286         DestroyWindow(hwnd);
5287     }
5288
5289     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5290                            0, 0, 50, 14, 0, 0, 0, NULL);
5291     ok(hwnd != 0, "Failed to create button window\n");
5292
5293     SetForegroundWindow(hwnd);
5294     flush_events();
5295
5296     SetActiveWindow(hwnd);
5297     SetFocus(0);
5298     flush_sequence();
5299
5300     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5301     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5302
5303     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5304     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5305
5306     flush_sequence();
5307     zfont = GetStockObject(SYSTEM_FONT);
5308     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5309     UpdateWindow(hwnd);
5310     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5311
5312     DestroyWindow(hwnd);
5313 }
5314
5315 /****************** static message test *************************/
5316 static const struct message WmSetFontStaticSeq[] =
5317 {
5318     { WM_SETFONT, sent },
5319     { WM_PAINT, sent|defwinproc|optional },
5320     { WM_ERASEBKGND, sent|defwinproc|optional },
5321     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5322     { 0 }
5323 };
5324
5325 static WNDPROC old_static_proc;
5326
5327 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5328 {
5329     static long defwndproc_counter = 0;
5330     LRESULT ret;
5331     struct recvd_message msg;
5332
5333     if (ignore_message( message )) return 0;
5334
5335     msg.hwnd = hwnd;
5336     msg.message = message;
5337     msg.flags = sent|wparam|lparam;
5338     if (defwndproc_counter) msg.flags |= defwinproc;
5339     msg.wParam = wParam;
5340     msg.lParam = lParam;
5341     msg.descr = "static";
5342     add_message(&msg);
5343
5344     defwndproc_counter++;
5345     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5346     defwndproc_counter--;
5347
5348     return ret;
5349 }
5350
5351 static void subclass_static(void)
5352 {
5353     WNDCLASSA cls;
5354
5355     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5356
5357     old_static_proc = cls.lpfnWndProc;
5358
5359     cls.hInstance = GetModuleHandle(0);
5360     cls.lpfnWndProc = static_hook_proc;
5361     cls.lpszClassName = "my_static_class";
5362     UnregisterClass(cls.lpszClassName, cls.hInstance);
5363     if (!RegisterClassA(&cls)) assert(0);
5364 }
5365
5366 static void test_static_messages(void)
5367 {
5368     /* FIXME: make as comprehensive as the button message test */
5369     static const struct
5370     {
5371         DWORD style;
5372         DWORD dlg_code;
5373         const struct message *setfont;
5374     } static_ctrl[] = {
5375         { SS_LEFT, DLGC_STATIC,
5376           WmSetFontStaticSeq }
5377     };
5378     unsigned int i;
5379     HWND hwnd;
5380     DWORD dlg_code;
5381
5382     subclass_static();
5383
5384     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5385     {
5386         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5387                                0, 0, 50, 14, 0, 0, 0, NULL);
5388         ok(hwnd != 0, "Failed to create static window\n");
5389
5390         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5391         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5392
5393         ShowWindow(hwnd, SW_SHOW);
5394         UpdateWindow(hwnd);
5395         SetFocus(0);
5396         flush_sequence();
5397
5398         trace("static style %08x\n", static_ctrl[i].style);
5399         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5400         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5401
5402         DestroyWindow(hwnd);
5403     }
5404 }
5405
5406 /****************** ComboBox message test *************************/
5407 #define ID_COMBOBOX 0x000f
5408
5409 static const struct message WmKeyDownComboSeq[] =
5410 {
5411     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5412     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5413     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5414     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5415     { WM_CTLCOLOREDIT, sent|parent },
5416     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5417     { 0 }
5418 };
5419
5420 static WNDPROC old_combobox_proc;
5421
5422 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5423 {
5424     static long defwndproc_counter = 0;
5425     LRESULT ret;
5426     struct recvd_message msg;
5427
5428     /* do not log painting messages */
5429     if (message != WM_PAINT &&
5430         message != WM_NCPAINT &&
5431         message != WM_SYNCPAINT &&
5432         message != WM_ERASEBKGND &&
5433         message != WM_NCHITTEST &&
5434         message != WM_GETTEXT &&
5435         !ignore_message( message ))
5436     {
5437         msg.hwnd = hwnd;
5438         msg.message = message;
5439         msg.flags = sent|wparam|lparam;
5440         if (defwndproc_counter) msg.flags |= defwinproc;
5441         msg.wParam = wParam;
5442         msg.lParam = lParam;
5443         msg.descr = "combo";
5444         add_message(&msg);
5445     }
5446
5447     defwndproc_counter++;
5448     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5449     defwndproc_counter--;
5450
5451     return ret;
5452 }
5453
5454 static void subclass_combobox(void)
5455 {
5456     WNDCLASSA cls;
5457
5458     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5459
5460     old_combobox_proc = cls.lpfnWndProc;
5461
5462     cls.hInstance = GetModuleHandle(0);
5463     cls.lpfnWndProc = combobox_hook_proc;
5464     cls.lpszClassName = "my_combobox_class";
5465     UnregisterClass(cls.lpszClassName, cls.hInstance);
5466     if (!RegisterClassA(&cls)) assert(0);
5467 }
5468
5469 static void test_combobox_messages(void)
5470 {
5471     HWND parent, combo;
5472     LRESULT ret;
5473
5474     subclass_combobox();
5475
5476     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5477                              100, 100, 200, 200, 0, 0, 0, NULL);
5478     ok(parent != 0, "Failed to create parent window\n");
5479     flush_sequence();
5480
5481     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5482                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5483     ok(combo != 0, "Failed to create combobox window\n");
5484
5485     UpdateWindow(combo);
5486
5487     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5488     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5489
5490     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5491     ok(ret == 0, "expected 0, got %ld\n", ret);
5492     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5493     ok(ret == 1, "expected 1, got %ld\n", ret);
5494     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5495     ok(ret == 2, "expected 2, got %ld\n", ret);
5496
5497     SendMessage(combo, CB_SETCURSEL, 0, 0);
5498     SetFocus(combo);
5499     flush_sequence();
5500
5501     log_all_parent_messages++;
5502     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5503     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5504     log_all_parent_messages--;
5505     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5506
5507     DestroyWindow(combo);
5508     DestroyWindow(parent);
5509 }
5510
5511 /****************** WM_IME_KEYDOWN message test *******************/
5512
5513 static const struct message WmImeKeydownMsgSeq_0[] =
5514 {
5515     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5516     { WM_CHAR, wparam, 'A' },
5517     { 0 }
5518 };
5519
5520 static const struct message WmImeKeydownMsgSeq_1[] =
5521 {
5522     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5523     { WM_CHAR,    optional|wparam, VK_RETURN },
5524     { 0 }
5525 };
5526
5527 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5528 {
5529     struct recvd_message msg;
5530
5531     msg.hwnd = hwnd;
5532     msg.message = message;
5533     msg.flags = wparam|lparam;
5534     msg.wParam = wParam;
5535     msg.lParam = lParam;
5536     msg.descr = "wmime_keydown";
5537     add_message(&msg);
5538
5539     return DefWindowProcA(hwnd, message, wParam, lParam);
5540 }
5541
5542 static void register_wmime_keydown_class(void)
5543 {
5544     WNDCLASSA cls;
5545
5546     ZeroMemory(&cls, sizeof(WNDCLASSA));
5547     cls.lpfnWndProc = wmime_keydown_procA;
5548     cls.hInstance = GetModuleHandleA(0);
5549     cls.lpszClassName = "wmime_keydown_class";
5550     if (!RegisterClassA(&cls)) assert(0);
5551 }
5552
5553 static void test_wmime_keydown_message(void)
5554 {
5555     HWND hwnd;
5556     MSG msg;
5557
5558     trace("Message sequences by WM_IME_KEYDOWN\n");
5559
5560     register_wmime_keydown_class();
5561     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5562                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5563                            NULL, NULL, 0);
5564     flush_events();
5565     flush_sequence();
5566
5567     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5568     SendMessage(hwnd, WM_CHAR, 'A', 1);
5569     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5570
5571     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5572     {
5573         TranslateMessage(&msg);
5574         DispatchMessage(&msg);
5575     }
5576     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5577
5578     DestroyWindow(hwnd);
5579 }
5580
5581 /************* painting message test ********************/
5582
5583 void dump_region(HRGN hrgn)
5584 {
5585     DWORD i, size;
5586     RGNDATA *data = NULL;
5587     RECT *rect;
5588
5589     if (!hrgn)
5590     {
5591         printf( "null region\n" );
5592         return;
5593     }
5594     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5595     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5596     GetRegionData( hrgn, size, data );
5597     printf("%d rects:", data->rdh.nCount );
5598     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5599         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5600     printf("\n");
5601     HeapFree( GetProcessHeap(), 0, data );
5602 }
5603
5604 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5605 {
5606     INT ret;
5607     RECT r1, r2;
5608     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5609     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5610
5611     ret = GetUpdateRgn( hwnd, update, FALSE );
5612     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5613     if (ret == NULLREGION)
5614     {
5615         ok( !hrgn, "Update region shouldn't be empty\n" );
5616     }
5617     else
5618     {
5619         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5620         {
5621             ok( 0, "Regions are different\n" );
5622             if (winetest_debug > 0)
5623             {
5624                 printf( "Update region: " );
5625                 dump_region( update );
5626                 printf( "Wanted region: " );
5627                 dump_region( hrgn );
5628             }
5629         }
5630     }
5631     GetRgnBox( update, &r1 );
5632     GetUpdateRect( hwnd, &r2, FALSE );
5633     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5634         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5635         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5636
5637     DeleteObject( tmp );
5638     DeleteObject( update );
5639 }
5640
5641 static const struct message WmInvalidateRgn[] = {
5642     { WM_NCPAINT, sent },
5643     { WM_GETTEXT, sent|defwinproc|optional },
5644     { 0 }
5645 };
5646
5647 static const struct message WmGetUpdateRect[] = {
5648     { WM_NCPAINT, sent },
5649     { WM_GETTEXT, sent|defwinproc|optional },
5650     { WM_PAINT, sent },
5651     { 0 }
5652 };
5653
5654 static const struct message WmInvalidateFull[] = {
5655     { WM_NCPAINT, sent|wparam, 1 },
5656     { WM_GETTEXT, sent|defwinproc|optional },
5657     { 0 }
5658 };
5659
5660 static const struct message WmInvalidateErase[] = {
5661     { WM_NCPAINT, sent|wparam, 1 },
5662     { WM_GETTEXT, sent|defwinproc|optional },
5663     { WM_ERASEBKGND, sent },
5664     { 0 }
5665 };
5666
5667 static const struct message WmInvalidatePaint[] = {
5668     { WM_PAINT, sent },
5669     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5670     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5671     { 0 }
5672 };
5673
5674 static const struct message WmInvalidateErasePaint[] = {
5675     { WM_PAINT, sent },
5676     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5677     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5678     { WM_ERASEBKGND, sent|beginpaint|optional },
5679     { 0 }
5680 };
5681
5682 static const struct message WmInvalidateErasePaint2[] = {
5683     { WM_PAINT, sent },
5684     { WM_NCPAINT, sent|beginpaint },
5685     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5686     { WM_ERASEBKGND, sent|beginpaint|optional },
5687     { 0 }
5688 };
5689
5690 static const struct message WmErase[] = {
5691     { WM_ERASEBKGND, sent },
5692     { 0 }
5693 };
5694
5695 static const struct message WmPaint[] = {
5696     { WM_PAINT, sent },
5697     { 0 }
5698 };
5699
5700 static const struct message WmParentOnlyPaint[] = {
5701     { WM_PAINT, sent|parent },
5702     { 0 }
5703 };
5704
5705 static const struct message WmInvalidateParent[] = {
5706     { WM_NCPAINT, sent|parent },
5707     { WM_GETTEXT, sent|defwinproc|parent|optional },
5708     { WM_ERASEBKGND, sent|parent },
5709     { 0 }
5710 };
5711
5712 static const struct message WmInvalidateParentChild[] = {
5713     { WM_NCPAINT, sent|parent },
5714     { WM_GETTEXT, sent|defwinproc|parent|optional },
5715     { WM_ERASEBKGND, sent|parent },
5716     { WM_NCPAINT, sent },
5717     { WM_GETTEXT, sent|defwinproc|optional },
5718     { WM_ERASEBKGND, sent },
5719     { 0 }
5720 };
5721
5722 static const struct message WmInvalidateParentChild2[] = {
5723     { WM_ERASEBKGND, sent|parent },
5724     { WM_NCPAINT, sent },
5725     { WM_GETTEXT, sent|defwinproc|optional },
5726     { WM_ERASEBKGND, sent },
5727     { 0 }
5728 };
5729
5730 static const struct message WmParentPaint[] = {
5731     { WM_PAINT, sent|parent },
5732     { WM_PAINT, sent },
5733     { 0 }
5734 };
5735
5736 static const struct message WmParentPaintNc[] = {
5737     { WM_PAINT, sent|parent },
5738     { WM_PAINT, sent },
5739     { WM_NCPAINT, sent|beginpaint },
5740     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5741     { WM_ERASEBKGND, sent|beginpaint|optional },
5742     { 0 }
5743 };
5744
5745 static const struct message WmChildPaintNc[] = {
5746     { WM_PAINT, sent },
5747     { WM_NCPAINT, sent|beginpaint },
5748     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5749     { WM_ERASEBKGND, sent|beginpaint|optional },
5750     { 0 }
5751 };
5752
5753 static const struct message WmParentErasePaint[] = {
5754     { WM_PAINT, sent|parent },
5755     { WM_NCPAINT, sent|parent|beginpaint },
5756     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5757     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
5758     { WM_PAINT, sent },
5759     { WM_NCPAINT, sent|beginpaint },
5760     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5761     { WM_ERASEBKGND, sent|beginpaint|optional },
5762     { 0 }
5763 };
5764
5765 static const struct message WmParentOnlyNcPaint[] = {
5766     { WM_PAINT, sent|parent },
5767     { WM_NCPAINT, sent|parent|beginpaint },
5768     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5769     { 0 }
5770 };
5771
5772 static const struct message WmSetParentStyle[] = {
5773     { WM_STYLECHANGING, sent|parent },
5774     { WM_STYLECHANGED, sent|parent },
5775     { 0 }
5776 };
5777
5778 static void test_paint_messages(void)
5779 {
5780     BOOL ret;
5781     RECT rect;
5782     POINT pt;
5783     MSG msg;
5784     HWND hparent, hchild;
5785     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5786     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5787     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5788                                 100, 100, 200, 200, 0, 0, 0, NULL);
5789     ok (hwnd != 0, "Failed to create overlapped window\n");
5790
5791     ShowWindow( hwnd, SW_SHOW );
5792     UpdateWindow( hwnd );
5793     flush_events();
5794     flush_sequence();
5795
5796     check_update_rgn( hwnd, 0 );
5797     SetRectRgn( hrgn, 10, 10, 20, 20 );
5798     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5799     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5800     check_update_rgn( hwnd, hrgn );
5801     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5802     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5803     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5804     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5805     check_update_rgn( hwnd, hrgn );
5806     /* validate everything */
5807     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5808     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5809     check_update_rgn( hwnd, 0 );
5810
5811     /* test empty region */
5812     SetRectRgn( hrgn, 10, 10, 10, 15 );
5813     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5814     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5815     check_update_rgn( hwnd, 0 );
5816     /* test empty rect */
5817     SetRect( &rect, 10, 10, 10, 15 );
5818     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5819     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5820     check_update_rgn( hwnd, 0 );
5821
5822     /* flush pending messages */
5823     flush_events();
5824     flush_sequence();
5825
5826     GetClientRect( hwnd, &rect );
5827     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5828     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5829      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5830      */
5831     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5832     SetRectEmpty( &rect );
5833     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5834     check_update_rgn( hwnd, hrgn );
5835     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5836     flush_events();
5837     ok_sequence( WmPaint, "Paint", FALSE );
5838     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5839     check_update_rgn( hwnd, 0 );
5840
5841     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5842      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5843      */
5844     trace("testing ValidateRect(0, NULL)\n");
5845     SetRectEmpty( &rect );
5846     if (ValidateRect(0, &rect))  /* not supported on Win9x */
5847     {
5848         check_update_rgn( hwnd, hrgn );
5849         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5850         flush_events();
5851         ok_sequence( WmPaint, "Paint", FALSE );
5852         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5853         check_update_rgn( hwnd, 0 );
5854     }
5855
5856     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5857     SetLastError(0xdeadbeef);
5858     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5859     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5860        "wrong error code %d\n", GetLastError());
5861     check_update_rgn( hwnd, 0 );
5862     flush_events();
5863     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5864
5865     trace("testing ValidateRgn(0, NULL)\n");
5866     SetLastError(0xdeadbeef);
5867     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5868     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
5869        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
5870        "wrong error code %d\n", GetLastError());
5871     check_update_rgn( hwnd, 0 );
5872     flush_events();
5873     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5874
5875     /* now with frame */
5876     SetRectRgn( hrgn, -5, -5, 20, 20 );
5877
5878     /* flush pending messages */
5879     flush_events();
5880     flush_sequence();
5881     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5882     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5883
5884     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5885     check_update_rgn( hwnd, hrgn );
5886
5887     flush_sequence();
5888     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5889     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5890
5891     flush_sequence();
5892     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5893     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5894
5895     GetClientRect( hwnd, &rect );
5896     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5897     check_update_rgn( hwnd, hrgn );
5898
5899     flush_sequence();
5900     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5901     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5902
5903     flush_sequence();
5904     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5905     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5906     check_update_rgn( hwnd, 0 );
5907
5908     flush_sequence();
5909     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5910     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5911     check_update_rgn( hwnd, 0 );
5912
5913     flush_sequence();
5914     SetRectRgn( hrgn, 0, 0, 100, 100 );
5915     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5916     SetRectRgn( hrgn, 0, 0, 50, 100 );
5917     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5918     SetRectRgn( hrgn, 50, 0, 100, 100 );
5919     check_update_rgn( hwnd, hrgn );
5920     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5921     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5922     check_update_rgn( hwnd, 0 );
5923
5924     flush_sequence();
5925     SetRectRgn( hrgn, 0, 0, 100, 100 );
5926     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5927     SetRectRgn( hrgn, 0, 0, 100, 50 );
5928     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5929     ok_sequence( WmErase, "Erase", FALSE );
5930     SetRectRgn( hrgn, 0, 50, 100, 100 );
5931     check_update_rgn( hwnd, hrgn );
5932
5933     flush_sequence();
5934     SetRectRgn( hrgn, 0, 0, 100, 100 );
5935     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5936     SetRectRgn( hrgn, 0, 0, 50, 50 );
5937     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5938     ok_sequence( WmPaint, "Paint", FALSE );
5939
5940     flush_sequence();
5941     SetRectRgn( hrgn, -4, -4, -2, -2 );
5942     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5943     SetRectRgn( hrgn, -200, -200, -198, -198 );
5944     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5945     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5946
5947     flush_sequence();
5948     SetRectRgn( hrgn, -4, -4, -2, -2 );
5949     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5950     SetRectRgn( hrgn, -4, -4, -3, -3 );
5951     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5952     SetRectRgn( hrgn, 0, 0, 1, 1 );
5953     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5954     ok_sequence( WmPaint, "Paint", FALSE );
5955
5956     flush_sequence();
5957     SetRectRgn( hrgn, -4, -4, -1, -1 );
5958     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5959     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5960     /* make sure no WM_PAINT was generated */
5961     flush_events();
5962     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5963
5964     flush_sequence();
5965     SetRectRgn( hrgn, -4, -4, -1, -1 );
5966     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5967     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5968     {
5969         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5970         {
5971             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5972             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5973             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5974             ret = GetUpdateRect( hwnd, &rect, FALSE );
5975             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5976             /* this will send WM_NCPAINT and validate the non client area */
5977             ret = GetUpdateRect( hwnd, &rect, TRUE );
5978             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5979         }
5980         DispatchMessage( &msg );
5981     }
5982     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5983
5984     DestroyWindow( hwnd );
5985
5986     /* now test with a child window */
5987
5988     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5989                               100, 100, 200, 200, 0, 0, 0, NULL);
5990     ok (hparent != 0, "Failed to create parent window\n");
5991
5992     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5993                            10, 10, 100, 100, hparent, 0, 0, NULL);
5994     ok (hchild != 0, "Failed to create child window\n");
5995
5996     ShowWindow( hparent, SW_SHOW );
5997     UpdateWindow( hparent );
5998     UpdateWindow( hchild );
5999     flush_events();
6000     flush_sequence();
6001     log_all_parent_messages++;
6002
6003     SetRect( &rect, 0, 0, 50, 50 );
6004     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6005     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6006     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6007
6008     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6009     pt.x = pt.y = 0;
6010     MapWindowPoints( hchild, hparent, &pt, 1 );
6011     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6012     check_update_rgn( hchild, hrgn );
6013     SetRectRgn( hrgn, 0, 0, 50, 50 );
6014     check_update_rgn( hparent, hrgn );
6015     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6016     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6017     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6018     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6019
6020     flush_events();
6021     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6022
6023     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6024     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6025     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6026     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6027     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6028
6029     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6030     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6031     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6032
6033     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6034     flush_sequence();
6035     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6036     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6037     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6038
6039     /* flush all paint messages */
6040     flush_events();
6041     flush_sequence();
6042
6043     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6044     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6045     SetRectRgn( hrgn, 0, 0, 50, 50 );
6046     check_update_rgn( hparent, hrgn );
6047     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6048     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6049     SetRectRgn( hrgn, 0, 0, 50, 50 );
6050     check_update_rgn( hparent, hrgn );
6051
6052     /* flush all paint messages */
6053     flush_events();
6054     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6055     flush_sequence();
6056
6057     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6058     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6059     SetRectRgn( hrgn, 0, 0, 50, 50 );
6060     check_update_rgn( hparent, hrgn );
6061     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6062     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6063     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6064     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6065     check_update_rgn( hparent, hrgn );
6066     /* flush all paint messages */
6067     flush_events();
6068     flush_sequence();
6069
6070     /* same as above but parent gets completely validated */
6071     SetRect( &rect, 20, 20, 30, 30 );
6072     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6073     SetRectRgn( hrgn, 20, 20, 30, 30 );
6074     check_update_rgn( hparent, hrgn );
6075     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6076     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6077     check_update_rgn( hparent, 0 );  /* no update region */
6078     flush_events();
6079     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6080
6081     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6082     flush_sequence();
6083     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6084     SetRectRgn( hrgn, 20, 20, 30, 30 );
6085     check_update_rgn( hparent, hrgn );
6086     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6087     SetRectRgn( hrgn, 20, 20, 30, 30 );
6088     check_update_rgn( hparent, hrgn );
6089
6090     /* same as above but normal WM_PAINT doesn't validate parent */
6091     flush_sequence();
6092     SetRect( &rect, 20, 20, 30, 30 );
6093     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6094     SetRectRgn( hrgn, 20, 20, 30, 30 );
6095     check_update_rgn( hparent, hrgn );
6096     /* no WM_PAINT in child while parent still pending */
6097     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6098     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6099     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6100     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6101
6102     flush_sequence();
6103     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6104     /* no WM_PAINT in child while parent still pending */
6105     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6106     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6107     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6108     /* now that parent is valid child should get WM_PAINT */
6109     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6110     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6111     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6112     ok_sequence( WmEmptySeq, "No other message", FALSE );
6113
6114     /* same thing with WS_CLIPCHILDREN in parent */
6115     flush_sequence();
6116     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6117     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6118     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6119     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6120     ok_sequence( WmEmptySeq, "No message", FALSE );
6121     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6122     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6123
6124     flush_sequence();
6125     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6126     SetRectRgn( hrgn, 20, 20, 30, 30 );
6127     check_update_rgn( hparent, hrgn );
6128     /* no WM_PAINT in child while parent still pending */
6129     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6130     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6131     /* WM_PAINT in parent first */
6132     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6133     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6134
6135     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6136     flush_sequence();
6137     SetRect( &rect, 0, 0, 30, 30 );
6138     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6139     SetRectRgn( hrgn, 0, 0, 30, 30 );
6140     check_update_rgn( hparent, hrgn );
6141     flush_events();
6142     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6143
6144     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6145     flush_sequence();
6146     SetRect( &rect, -10, 0, 30, 30 );
6147     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6148     SetRect( &rect, 0, 0, 20, 20 );
6149     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6150     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6151     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6152
6153     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6154     flush_sequence();
6155     SetRect( &rect, -10, 0, 30, 30 );
6156     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6157     SetRect( &rect, 0, 0, 100, 100 );
6158     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6159     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6160     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6161     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6162     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6163
6164     /* test RDW_INTERNALPAINT behavior */
6165
6166     flush_sequence();
6167     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6168     flush_events();
6169     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6170
6171     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6172     flush_events();
6173     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6174
6175     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6176     flush_events();
6177     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6178
6179     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6180     UpdateWindow( hparent );
6181     flush_events();
6182     flush_sequence();
6183     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6184     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6185     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6186                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6187     flush_events();
6188     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6189
6190     UpdateWindow( hparent );
6191     flush_events();
6192     flush_sequence();
6193     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6194     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6195     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6196                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6197     flush_events();
6198     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6199
6200     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6201     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6202     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6203     flush_events();
6204     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6205
6206     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6207     UpdateWindow( hparent );
6208     flush_events();
6209     flush_sequence();
6210     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6211     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6212     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6213                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6214     flush_events();
6215     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6216
6217     UpdateWindow( hparent );
6218     flush_events();
6219     flush_sequence();
6220     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6221     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6222     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6223                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6224     flush_events();
6225     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6226
6227     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6228     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6229
6230     UpdateWindow( hparent );
6231     flush_events();
6232     flush_sequence();
6233     trace("testing SetWindowPos(-10000, -10000) on child\n");
6234     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6235     check_update_rgn( hchild, 0 );
6236     flush_events();
6237
6238 #if 0 /* this one doesn't pass under Wine yet */
6239     UpdateWindow( hparent );
6240     flush_events();
6241     flush_sequence();
6242     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6243     ShowWindow( hchild, SW_MINIMIZE );
6244     check_update_rgn( hchild, 0 );
6245     flush_events();
6246 #endif
6247
6248     UpdateWindow( hparent );
6249     flush_events();
6250     flush_sequence();
6251     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6252     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6253     check_update_rgn( hparent, 0 );
6254     flush_events();
6255
6256     log_all_parent_messages--;
6257     DestroyWindow( hparent );
6258     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6259
6260     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6261
6262     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6263                               100, 100, 200, 200, 0, 0, 0, NULL);
6264     ok (hparent != 0, "Failed to create parent window\n");
6265
6266     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6267                            10, 10, 100, 100, hparent, 0, 0, NULL);
6268     ok (hchild != 0, "Failed to create child window\n");
6269
6270     ShowWindow( hparent, SW_SHOW );
6271     UpdateWindow( hparent );
6272     UpdateWindow( hchild );
6273     flush_events();
6274     flush_sequence();
6275
6276     /* moving child outside of parent boundaries changes update region */
6277     SetRect( &rect, 0, 0, 40, 40 );
6278     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6279     SetRectRgn( hrgn, 0, 0, 40, 40 );
6280     check_update_rgn( hchild, hrgn );
6281     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6282     SetRectRgn( hrgn, 10, 0, 40, 40 );
6283     check_update_rgn( hchild, hrgn );
6284     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6285     SetRectRgn( hrgn, 10, 10, 40, 40 );
6286     check_update_rgn( hchild, hrgn );
6287
6288     /* moving parent off-screen does too */
6289     SetRect( &rect, 0, 0, 100, 100 );
6290     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6291     SetRectRgn( hrgn, 0, 0, 100, 100 );
6292     check_update_rgn( hparent, hrgn );
6293     SetRectRgn( hrgn, 10, 10, 40, 40 );
6294     check_update_rgn( hchild, hrgn );
6295     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6296     SetRectRgn( hrgn, 20, 20, 100, 100 );
6297     check_update_rgn( hparent, hrgn );
6298     SetRectRgn( hrgn, 30, 30, 40, 40 );
6299     check_update_rgn( hchild, hrgn );
6300
6301     /* invalidated region is cropped by the parent rects */
6302     SetRect( &rect, 0, 0, 50, 50 );
6303     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6304     SetRectRgn( hrgn, 30, 30, 50, 50 );
6305     check_update_rgn( hchild, hrgn );
6306
6307     DestroyWindow( hparent );
6308     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6309     flush_sequence();
6310
6311     DeleteObject( hrgn );
6312     DeleteObject( hrgn2 );
6313 }
6314
6315 struct wnd_event
6316 {
6317     HWND hwnd;
6318     HANDLE grand_child;
6319     HANDLE start_event;
6320     HANDLE stop_event;
6321 };
6322
6323 static DWORD WINAPI thread_proc(void *param)
6324 {
6325     MSG msg;
6326     struct wnd_event *wnd_event = param;
6327
6328     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6329                                       100, 100, 200, 200, 0, 0, 0, NULL);
6330     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6331
6332     SetEvent(wnd_event->start_event);
6333
6334     while (GetMessage(&msg, 0, 0, 0))
6335     {
6336         TranslateMessage(&msg);
6337         DispatchMessage(&msg);
6338     }
6339
6340     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6341
6342     return 0;
6343 }
6344
6345 static DWORD CALLBACK create_grand_child_thread( void *param )
6346 {
6347     struct wnd_event *wnd_event = param;
6348     HWND hchild;
6349     MSG msg;
6350
6351     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6352                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6353     ok (hchild != 0, "Failed to create child window\n");
6354     flush_events();
6355     flush_sequence();
6356     SetEvent( wnd_event->start_event );
6357
6358     for (;;)
6359     {
6360         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6361         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6362         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6363     }
6364     return 0;
6365 }
6366
6367 static DWORD CALLBACK create_child_thread( void *param )
6368 {
6369     struct wnd_event *wnd_event = param;
6370     struct wnd_event child_event;
6371     DWORD ret, tid;
6372     MSG msg;
6373
6374     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6375                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6376     ok (child_event.hwnd != 0, "Failed to create child window\n");
6377     SetFocus( child_event.hwnd );
6378     flush_events();
6379     flush_sequence();
6380     child_event.start_event = wnd_event->start_event;
6381     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6382     for (;;)
6383     {
6384         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6385         if (ret != 1) break;
6386         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6387     }
6388     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6389     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6390     return 0;
6391 }
6392
6393 static void test_interthread_messages(void)
6394 {
6395     HANDLE hThread;
6396     DWORD tid;
6397     WNDPROC proc;
6398     MSG msg;
6399     char buf[256];
6400     int len, expected_len;
6401     struct wnd_event wnd_event;
6402     BOOL ret;
6403
6404     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6405     if (!wnd_event.start_event)
6406     {
6407         win_skip("skipping interthread message test under win9x\n");
6408         return;
6409     }
6410
6411     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6412     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6413
6414     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6415
6416     CloseHandle(wnd_event.start_event);
6417
6418     SetLastError(0xdeadbeef);
6419     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6420     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6421        "wrong error code %d\n", GetLastError());
6422
6423     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6424     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6425
6426     expected_len = lstrlenA("window caption text");
6427     memset(buf, 0, sizeof(buf));
6428     SetLastError(0xdeadbeef);
6429     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6430     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6431     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6432
6433     msg.hwnd = wnd_event.hwnd;
6434     msg.message = WM_GETTEXT;
6435     msg.wParam = sizeof(buf);
6436     msg.lParam = (LPARAM)buf;
6437     memset(buf, 0, sizeof(buf));
6438     SetLastError(0xdeadbeef);
6439     len = DispatchMessageA(&msg);
6440     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6441        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6442
6443     /* the following test causes an exception in user.exe under win9x */
6444     msg.hwnd = wnd_event.hwnd;
6445     msg.message = WM_TIMER;
6446     msg.wParam = 0;
6447     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6448     SetLastError(0xdeadbeef);
6449     len = DispatchMessageA(&msg);
6450     ok(!len && GetLastError() == 0xdeadbeef,
6451        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6452
6453     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6454     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6455
6456     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6457     CloseHandle(hThread);
6458
6459     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6460
6461     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6462                               100, 100, 200, 200, 0, 0, 0, NULL);
6463     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6464     flush_sequence();
6465     log_all_parent_messages++;
6466     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6467     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6468     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6469     for (;;)
6470     {
6471         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6472         if (ret != 1) break;
6473         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6474     }
6475     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6476     /* now wait for the thread without processing messages; this shouldn't deadlock */
6477     SetEvent( wnd_event.stop_event );
6478     ret = WaitForSingleObject( hThread, 5000 );
6479     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6480     CloseHandle( hThread );
6481
6482     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6483     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6484     CloseHandle( wnd_event.grand_child );
6485
6486     CloseHandle( wnd_event.start_event );
6487     CloseHandle( wnd_event.stop_event );
6488     flush_events();
6489     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6490     log_all_parent_messages--;
6491     DestroyWindow( wnd_event.hwnd );
6492 }
6493
6494
6495 static const struct message WmVkN[] = {
6496     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6497     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6498     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6499     { WM_CHAR, wparam|lparam, 'n', 1 },
6500     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6501     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6502     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6503     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6504     { 0 }
6505 };
6506 static const struct message WmShiftVkN[] = {
6507     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6508     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6509     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6510     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6511     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6512     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6513     { WM_CHAR, wparam|lparam, 'N', 1 },
6514     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6515     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6516     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6517     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6518     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6519     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6520     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6521     { 0 }
6522 };
6523 static const struct message WmCtrlVkN[] = {
6524     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6525     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6526     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6527     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6528     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6529     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6530     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6531     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6532     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6533     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6534     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6535     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6536     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6537     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6538     { 0 }
6539 };
6540 static const struct message WmCtrlVkN_2[] = {
6541     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6542     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6543     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6544     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6545     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6546     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6547     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6548     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6549     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6550     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6551     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6552     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6553     { 0 }
6554 };
6555 static const struct message WmAltVkN[] = {
6556     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6557     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6558     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6559     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6560     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6561     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6562     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6563     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6564     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6565     { HCBT_SYSCOMMAND, hook },
6566     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6567     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6568     { 0x00AE, sent|defwinproc|optional }, /* XP */
6569     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6570     { WM_INITMENU, sent|defwinproc },
6571     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6572     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6573     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6574     { WM_CAPTURECHANGED, sent|defwinproc },
6575     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6576     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6577     { WM_EXITMENULOOP, sent|defwinproc },
6578     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6579     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6580     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6581     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6582     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6583     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6584     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6585     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6586     { 0 }
6587 };
6588 static const struct message WmAltVkN_2[] = {
6589     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6590     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6591     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6592     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6593     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6594     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6595     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6596     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6597     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6598     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6599     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6600     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6601     { 0 }
6602 };
6603 static const struct message WmCtrlAltVkN[] = {
6604     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6605     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6606     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6607     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6608     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6609     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6610     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6611     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6612     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6613     { WM_CHAR, optional },
6614     { WM_CHAR, sent|optional },
6615     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6616     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6617     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6618     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6619     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6620     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6621     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6622     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6623     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6624     { 0 }
6625 };
6626 static const struct message WmCtrlShiftVkN[] = {
6627     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6628     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6629     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6630     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6631     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6632     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6633     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6634     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6635     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6636     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6637     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6638     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6639     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6640     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6641     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6642     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6643     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6644     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6645     { 0 }
6646 };
6647 static const struct message WmCtrlAltShiftVkN[] = {
6648     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6649     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6650     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6651     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6652     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6653     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6654     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6655     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6656     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6657     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6658     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6659     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6660     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6661     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6662     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6663     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6664     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6665     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6666     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6667     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6668     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6669     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6670     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6671     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6672     { 0 }
6673 };
6674 static const struct message WmAltPressRelease[] = {
6675     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6676     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6677     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6678     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6679     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6680     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6681     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6682     { HCBT_SYSCOMMAND, hook },
6683     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6684     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6685     { WM_INITMENU, sent|defwinproc },
6686     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6687     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6688     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6689
6690     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6691
6692     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6693     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6694     { WM_CAPTURECHANGED, sent|defwinproc },
6695     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6696     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6697     { WM_EXITMENULOOP, sent|defwinproc },
6698     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6699     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6700     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6701     { 0 }
6702 };
6703 static const struct message WmShiftMouseButton[] = {
6704     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6705     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6706     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6707     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6708     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6709     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
6710     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
6711     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
6712     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
6713     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6714     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6715     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6716     { 0 }
6717 };
6718 static const struct message WmF1Seq[] = {
6719     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6720     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6721     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6722     { WM_KEYF1, wparam|lparam, 0, 0 },
6723     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6724     { WM_HELP, sent|defwinproc },
6725     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6726     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6727     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6728     { 0 }
6729 };
6730 static const struct message WmVkAppsSeq[] = {
6731     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6732     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6733     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6734     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6735     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6736     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6737     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6738     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6739     { 0 }
6740 };
6741
6742 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6743 {
6744     MSG msg;
6745
6746     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6747     {
6748         struct recvd_message log_msg;
6749
6750         /* ignore some unwanted messages */
6751         if (msg.message == WM_MOUSEMOVE ||
6752             msg.message == WM_TIMER ||
6753             ignore_message( msg.message ))
6754             continue;
6755
6756         log_msg.hwnd = msg.hwnd;
6757         log_msg.message = msg.message;
6758         log_msg.flags = wparam|lparam;
6759         log_msg.wParam = msg.wParam;
6760         log_msg.lParam = msg.lParam;
6761         log_msg.descr = "accel";
6762         add_message(&log_msg);
6763
6764         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6765         {
6766             TranslateMessage(&msg);
6767             DispatchMessage(&msg);
6768         }
6769     }
6770 }
6771
6772 static void test_accelerators(void)
6773 {
6774     RECT rc;
6775     POINT pt;
6776     SHORT state;
6777     HACCEL hAccel;
6778     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6779                                 100, 100, 200, 200, 0, 0, 0, NULL);
6780     BOOL ret;
6781
6782     assert(hwnd != 0);
6783     UpdateWindow(hwnd);
6784     flush_events();
6785     flush_sequence();
6786
6787     SetFocus(hwnd);
6788     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6789
6790     state = GetKeyState(VK_SHIFT);
6791     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6792     state = GetKeyState(VK_CAPITAL);
6793     ok(state == 0, "wrong CapsLock state %04x\n", state);
6794
6795     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6796     assert(hAccel != 0);
6797
6798     flush_events();
6799     pump_msg_loop(hwnd, 0);
6800     flush_sequence();
6801
6802     trace("testing VK_N press/release\n");
6803     flush_sequence();
6804     keybd_event('N', 0, 0, 0);
6805     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6806     pump_msg_loop(hwnd, hAccel);
6807     if (!sequence_cnt)  /* we didn't get any message */
6808     {
6809         skip( "queuing key events not supported\n" );
6810         goto done;
6811     }
6812     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6813
6814     trace("testing Shift+VK_N press/release\n");
6815     flush_sequence();
6816     keybd_event(VK_SHIFT, 0, 0, 0);
6817     keybd_event('N', 0, 0, 0);
6818     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6819     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6820     pump_msg_loop(hwnd, hAccel);
6821     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6822
6823     trace("testing Ctrl+VK_N press/release\n");
6824     flush_sequence();
6825     keybd_event(VK_CONTROL, 0, 0, 0);
6826     keybd_event('N', 0, 0, 0);
6827     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6828     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6829     pump_msg_loop(hwnd, hAccel);
6830     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6831
6832     trace("testing Alt+VK_N press/release\n");
6833     flush_sequence();
6834     keybd_event(VK_MENU, 0, 0, 0);
6835     keybd_event('N', 0, 0, 0);
6836     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6837     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6838     pump_msg_loop(hwnd, hAccel);
6839     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6840
6841     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6842     flush_sequence();
6843     keybd_event(VK_CONTROL, 0, 0, 0);
6844     keybd_event(VK_MENU, 0, 0, 0);
6845     keybd_event('N', 0, 0, 0);
6846     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6847     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6848     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6849     pump_msg_loop(hwnd, hAccel);
6850     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6851
6852     ret = DestroyAcceleratorTable(hAccel);
6853     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6854
6855     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6856     assert(hAccel != 0);
6857
6858     trace("testing VK_N press/release\n");
6859     flush_sequence();
6860     keybd_event('N', 0, 0, 0);
6861     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6862     pump_msg_loop(hwnd, hAccel);
6863     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6864
6865     trace("testing Shift+VK_N press/release\n");
6866     flush_sequence();
6867     keybd_event(VK_SHIFT, 0, 0, 0);
6868     keybd_event('N', 0, 0, 0);
6869     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6870     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6871     pump_msg_loop(hwnd, hAccel);
6872     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6873
6874     trace("testing Ctrl+VK_N press/release 2\n");
6875     flush_sequence();
6876     keybd_event(VK_CONTROL, 0, 0, 0);
6877     keybd_event('N', 0, 0, 0);
6878     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6879     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6880     pump_msg_loop(hwnd, hAccel);
6881     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6882
6883     trace("testing Alt+VK_N press/release 2\n");
6884     flush_sequence();
6885     keybd_event(VK_MENU, 0, 0, 0);
6886     keybd_event('N', 0, 0, 0);
6887     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6888     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6889     pump_msg_loop(hwnd, hAccel);
6890     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6891
6892     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6893     flush_sequence();
6894     keybd_event(VK_CONTROL, 0, 0, 0);
6895     keybd_event(VK_MENU, 0, 0, 0);
6896     keybd_event('N', 0, 0, 0);
6897     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6898     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6899     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6900     pump_msg_loop(hwnd, hAccel);
6901     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6902
6903     trace("testing Ctrl+Shift+VK_N press/release\n");
6904     flush_sequence();
6905     keybd_event(VK_CONTROL, 0, 0, 0);
6906     keybd_event(VK_SHIFT, 0, 0, 0);
6907     keybd_event('N', 0, 0, 0);
6908     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6909     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6910     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6911     pump_msg_loop(hwnd, hAccel);
6912     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6913
6914     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6915     flush_sequence();
6916     keybd_event(VK_CONTROL, 0, 0, 0);
6917     keybd_event(VK_MENU, 0, 0, 0);
6918     keybd_event(VK_SHIFT, 0, 0, 0);
6919     keybd_event('N', 0, 0, 0);
6920     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6921     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6922     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6923     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6924     pump_msg_loop(hwnd, hAccel);
6925     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6926
6927     ret = DestroyAcceleratorTable(hAccel);
6928     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6929     hAccel = 0;
6930
6931     trace("testing Alt press/release\n");
6932     flush_sequence();
6933     keybd_event(VK_MENU, 0, 0, 0);
6934     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6935     keybd_event(VK_MENU, 0, 0, 0);
6936     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6937     pump_msg_loop(hwnd, 0);
6938     /* this test doesn't pass in Wine for managed windows */
6939     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6940
6941     trace("testing VK_F1 press/release\n");
6942     keybd_event(VK_F1, 0, 0, 0);
6943     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6944     pump_msg_loop(hwnd, 0);
6945     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6946
6947     trace("testing VK_APPS press/release\n");
6948     keybd_event(VK_APPS, 0, 0, 0);
6949     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6950     pump_msg_loop(hwnd, 0);
6951     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6952
6953     trace("testing Shift+MouseButton press/release\n");
6954     /* first, move mouse pointer inside of the window client area */
6955     GetClientRect(hwnd, &rc);
6956     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6957     rc.left += (rc.right - rc.left)/2;
6958     rc.top += (rc.bottom - rc.top)/2;
6959     SetCursorPos(rc.left, rc.top);
6960     SetActiveWindow(hwnd);
6961
6962     flush_events();
6963     flush_sequence();
6964     GetCursorPos(&pt);
6965     if (pt.x == rc.left && pt.y == rc.top)
6966     {
6967         int i;
6968         keybd_event(VK_SHIFT, 0, 0, 0);
6969         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6970         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6971         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6972         pump_msg_loop(hwnd, 0);
6973         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
6974         if (i < sequence_cnt)
6975             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
6976         else
6977             skip( "Shift+MouseButton event didn't get to the window\n" );
6978     }
6979
6980 done:
6981     if (hAccel) DestroyAcceleratorTable(hAccel);
6982     DestroyWindow(hwnd);
6983 }
6984
6985 /************* window procedures ********************/
6986
6987 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6988                              WPARAM wParam, LPARAM lParam)
6989 {
6990     static LONG defwndproc_counter = 0;
6991     static LONG beginpaint_counter = 0;
6992     LRESULT ret;
6993     struct recvd_message msg;
6994
6995     if (ignore_message( message )) return 0;
6996
6997     switch (message)
6998     {
6999         case WM_ENABLE:
7000         {
7001             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7002             ok((BOOL)wParam == !(style & WS_DISABLED),
7003                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7004             break;
7005         }
7006
7007         case WM_CAPTURECHANGED:
7008             if (test_DestroyWindow_flag)
7009             {
7010                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7011                 if (style & WS_CHILD)
7012                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7013                 else if (style & WS_POPUP)
7014                     lParam = WND_POPUP_ID;
7015                 else
7016                     lParam = WND_PARENT_ID;
7017             }
7018             break;
7019
7020         case WM_NCDESTROY:
7021         {
7022             HWND capture;
7023
7024             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7025             capture = GetCapture();
7026             if (capture)
7027             {
7028                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7029                 trace("current capture %p, releasing...\n", capture);
7030                 ReleaseCapture();
7031             }
7032         }
7033         /* fall through */
7034         case WM_DESTROY:
7035             if (pGetAncestor)
7036                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7037             if (test_DestroyWindow_flag)
7038             {
7039                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7040                 if (style & WS_CHILD)
7041                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7042                 else if (style & WS_POPUP)
7043                     lParam = WND_POPUP_ID;
7044                 else
7045                     lParam = WND_PARENT_ID;
7046             }
7047             break;
7048
7049         /* test_accelerators() depends on this */
7050         case WM_NCHITTEST:
7051             return HTCLIENT;
7052
7053         /* ignore */
7054         case WM_MOUSEMOVE:
7055         case WM_MOUSEACTIVATE:
7056         case WM_NCMOUSEMOVE:
7057         case WM_SETCURSOR:
7058         case WM_IME_SELECT:
7059             return 0;
7060     }
7061
7062     msg.hwnd = hwnd;
7063     msg.message = message;
7064     msg.flags = sent|wparam|lparam;
7065     if (defwndproc_counter) msg.flags |= defwinproc;
7066     if (beginpaint_counter) msg.flags |= beginpaint;
7067     msg.wParam = wParam;
7068     msg.lParam = lParam;
7069     msg.descr = "MsgCheckProc";
7070     add_message(&msg);
7071
7072     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7073     {
7074         HWND parent = GetParent(hwnd);
7075         RECT rc;
7076         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7077
7078         GetClientRect(parent, &rc);
7079         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7080         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7081               minmax->ptReserved.x, minmax->ptReserved.y,
7082               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7083               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7084               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7085               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7086
7087         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7088            minmax->ptMaxSize.x, rc.right);
7089         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7090            minmax->ptMaxSize.y, rc.bottom);
7091     }
7092
7093     if (message == WM_PAINT)
7094     {
7095         PAINTSTRUCT ps;
7096         beginpaint_counter++;
7097         BeginPaint( hwnd, &ps );
7098         beginpaint_counter--;
7099         EndPaint( hwnd, &ps );
7100         return 0;
7101     }
7102
7103     defwndproc_counter++;
7104     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7105                   : DefWindowProcA(hwnd, message, wParam, lParam);
7106     defwndproc_counter--;
7107
7108     return ret;
7109 }
7110
7111 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7112 {
7113     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7114 }
7115
7116 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7117 {
7118     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7119 }
7120
7121 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7122 {
7123     static LONG defwndproc_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_QUERYENDSESSION:
7132     case WM_ENDSESSION:
7133         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7134         break;
7135     }
7136
7137     msg.hwnd = hwnd;
7138     msg.message = message;
7139     msg.flags = sent|wparam|lparam;
7140     if (defwndproc_counter) msg.flags |= defwinproc;
7141     msg.wParam = wParam;
7142     msg.lParam = lParam;
7143     msg.descr = "popup";
7144     add_message(&msg);
7145
7146     if (message == WM_CREATE)
7147     {
7148         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7149         SetWindowLongA(hwnd, GWL_STYLE, style);
7150     }
7151
7152     defwndproc_counter++;
7153     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7154     defwndproc_counter--;
7155
7156     return ret;
7157 }
7158
7159 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7160 {
7161     static LONG defwndproc_counter = 0;
7162     static LONG beginpaint_counter = 0;
7163     LRESULT ret;
7164     struct recvd_message msg;
7165
7166     if (ignore_message( message )) return 0;
7167
7168     if (log_all_parent_messages ||
7169         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7170         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7171         message == WM_ENABLE || message == WM_ENTERIDLE ||
7172         message == WM_DRAWITEM ||
7173         message == WM_IME_SETCONTEXT)
7174     {
7175         switch (message)
7176         {
7177             /* ignore */
7178             case WM_NCHITTEST:
7179                 return HTCLIENT;
7180             case WM_SETCURSOR:
7181             case WM_MOUSEMOVE:
7182             case WM_NCMOUSEMOVE:
7183                 return 0;
7184
7185             case WM_ERASEBKGND:
7186             {
7187                 RECT rc;
7188                 INT ret = GetClipBox((HDC)wParam, &rc);
7189
7190                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7191                        ret, rc.left, rc.top, rc.right, rc.bottom);
7192                 break;
7193             }
7194         }
7195
7196         msg.hwnd = hwnd;
7197         msg.message = message;
7198         msg.flags = sent|parent|wparam|lparam;
7199         if (defwndproc_counter) msg.flags |= defwinproc;
7200         if (beginpaint_counter) msg.flags |= beginpaint;
7201         msg.wParam = wParam;
7202         msg.lParam = lParam;
7203         msg.descr = "parent";
7204         add_message(&msg);
7205     }
7206
7207     if (message == WM_PAINT)
7208     {
7209         PAINTSTRUCT ps;
7210         beginpaint_counter++;
7211         BeginPaint( hwnd, &ps );
7212         beginpaint_counter--;
7213         EndPaint( hwnd, &ps );
7214         return 0;
7215     }
7216
7217     defwndproc_counter++;
7218     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7219     defwndproc_counter--;
7220
7221     return ret;
7222 }
7223
7224 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7225 {
7226     static LONG defwndproc_counter = 0;
7227     LRESULT ret;
7228     struct recvd_message msg;
7229
7230     if (ignore_message( message )) return 0;
7231
7232     if (test_def_id)
7233     {
7234         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7235         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7236         if (after_end_dialog)
7237             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7238         else
7239             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7240     }
7241
7242     msg.hwnd = hwnd;
7243     msg.message = message;
7244     msg.flags = sent|wparam|lparam;
7245     if (defwndproc_counter) msg.flags |= defwinproc;
7246     msg.wParam = wParam;
7247     msg.lParam = lParam;
7248     msg.descr = "dialog";
7249     add_message(&msg);
7250
7251     defwndproc_counter++;
7252     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7253     defwndproc_counter--;
7254
7255     return ret;
7256 }
7257
7258 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7259 {
7260     static LONG defwndproc_counter = 0;
7261     LRESULT ret;
7262     struct recvd_message msg;
7263
7264     /* log only specific messages we are interested in */
7265     switch (message)
7266     {
7267 #if 0 /* probably log these as well */
7268     case WM_ACTIVATE:
7269     case WM_SETFOCUS:
7270     case WM_KILLFOCUS:
7271 #endif
7272     case WM_SHOWWINDOW:
7273     case WM_SIZE:
7274     case WM_MOVE:
7275     case WM_GETMINMAXINFO:
7276     case WM_WINDOWPOSCHANGING:
7277     case WM_WINDOWPOSCHANGED:
7278         break;
7279
7280     default: /* ignore */
7281         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7282         return DefWindowProcA(hwnd, message, wParam, lParam);
7283     }
7284
7285     msg.hwnd = hwnd;
7286     msg.message = message;
7287     msg.flags = sent|wparam|lparam;
7288     if (defwndproc_counter) msg.flags |= defwinproc;
7289     msg.wParam = wParam;
7290     msg.lParam = lParam;
7291     msg.descr = "show";
7292     add_message(&msg);
7293
7294     defwndproc_counter++;
7295     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7296     defwndproc_counter--;
7297
7298     return ret;
7299 }
7300
7301 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7302 {
7303     switch (msg)
7304     {
7305         case WM_CREATE: return 0;
7306         case WM_PAINT:
7307         {
7308             MSG msg2;
7309             static int i = 0;
7310
7311             if (i < 256)
7312             {
7313                 i++;
7314                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7315                 {
7316                     TranslateMessage(&msg2);
7317                     DispatchMessage(&msg2);
7318                 }
7319                 i--;
7320             }
7321             else ok(broken(1), "infinite loop\n");
7322             if ( i == 0)
7323                 paint_loop_done = 1;
7324             return DefWindowProcA(hWnd,msg,wParam,lParam);
7325         }
7326     }
7327     return DefWindowProcA(hWnd,msg,wParam,lParam);
7328 }
7329
7330 static BOOL RegisterWindowClasses(void)
7331 {
7332     WNDCLASSA cls;
7333     WNDCLASSW clsW;
7334
7335     cls.style = 0;
7336     cls.lpfnWndProc = MsgCheckProcA;
7337     cls.cbClsExtra = 0;
7338     cls.cbWndExtra = 0;
7339     cls.hInstance = GetModuleHandleA(0);
7340     cls.hIcon = 0;
7341     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7342     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7343     cls.lpszMenuName = NULL;
7344     cls.lpszClassName = "TestWindowClass";
7345     if(!RegisterClassA(&cls)) return FALSE;
7346
7347     cls.lpfnWndProc = ShowWindowProcA;
7348     cls.lpszClassName = "ShowWindowClass";
7349     if(!RegisterClassA(&cls)) return FALSE;
7350
7351     cls.lpfnWndProc = PopupMsgCheckProcA;
7352     cls.lpszClassName = "TestPopupClass";
7353     if(!RegisterClassA(&cls)) return FALSE;
7354
7355     cls.lpfnWndProc = ParentMsgCheckProcA;
7356     cls.lpszClassName = "TestParentClass";
7357     if(!RegisterClassA(&cls)) return FALSE;
7358
7359     cls.lpfnWndProc = DefWindowProcA;
7360     cls.lpszClassName = "SimpleWindowClass";
7361     if(!RegisterClassA(&cls)) return FALSE;
7362
7363     cls.lpfnWndProc = PaintLoopProcA;
7364     cls.lpszClassName = "PaintLoopWindowClass";
7365     if(!RegisterClassA(&cls)) return FALSE;
7366
7367     cls.style = CS_NOCLOSE;
7368     cls.lpszClassName = "NoCloseWindowClass";
7369     if(!RegisterClassA(&cls)) return FALSE;
7370
7371     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7372     cls.style = 0;
7373     cls.hInstance = GetModuleHandleA(0);
7374     cls.hbrBackground = 0;
7375     cls.lpfnWndProc = TestDlgProcA;
7376     cls.lpszClassName = "TestDialogClass";
7377     if(!RegisterClassA(&cls)) return FALSE;
7378
7379     clsW.style = 0;
7380     clsW.lpfnWndProc = MsgCheckProcW;
7381     clsW.cbClsExtra = 0;
7382     clsW.cbWndExtra = 0;
7383     clsW.hInstance = GetModuleHandleW(0);
7384     clsW.hIcon = 0;
7385     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7386     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7387     clsW.lpszMenuName = NULL;
7388     clsW.lpszClassName = testWindowClassW;
7389     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7390
7391     return TRUE;
7392 }
7393
7394 static BOOL is_our_logged_class(HWND hwnd)
7395 {
7396     char buf[256];
7397
7398     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7399     {
7400         if (!lstrcmpiA(buf, "TestWindowClass") ||
7401             !lstrcmpiA(buf, "ShowWindowClass") ||
7402             !lstrcmpiA(buf, "TestParentClass") ||
7403             !lstrcmpiA(buf, "TestPopupClass") ||
7404             !lstrcmpiA(buf, "SimpleWindowClass") ||
7405             !lstrcmpiA(buf, "TestDialogClass") ||
7406             !lstrcmpiA(buf, "MDI_frame_class") ||
7407             !lstrcmpiA(buf, "MDI_client_class") ||
7408             !lstrcmpiA(buf, "MDI_child_class") ||
7409             !lstrcmpiA(buf, "my_button_class") ||
7410             !lstrcmpiA(buf, "my_edit_class") ||
7411             !lstrcmpiA(buf, "static") ||
7412             !lstrcmpiA(buf, "ListBox") ||
7413             !lstrcmpiA(buf, "ComboBox") ||
7414             !lstrcmpiA(buf, "MyDialogClass") ||
7415             !lstrcmpiA(buf, "#32770") ||
7416             !lstrcmpiA(buf, "#32768"))
7417         return TRUE;
7418     }
7419     return FALSE;
7420 }
7421
7422 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7423
7424     HWND hwnd;
7425
7426     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7427
7428     if (nCode == HCBT_CLICKSKIPPED)
7429     {
7430         /* ignore this event, XP sends it a lot when switching focus between windows */
7431         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7432     }
7433
7434     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7435     {
7436         struct recvd_message msg;
7437
7438         msg.hwnd = 0;
7439         msg.message = nCode;
7440         msg.flags = hook|wparam|lparam;
7441         msg.wParam = wParam;
7442         msg.lParam = lParam;
7443         msg.descr = "CBT";
7444         add_message(&msg);
7445
7446         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7447     }
7448
7449     if (nCode == HCBT_DESTROYWND)
7450     {
7451         if (test_DestroyWindow_flag)
7452         {
7453             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7454             if (style & WS_CHILD)
7455                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7456             else if (style & WS_POPUP)
7457                 lParam = WND_POPUP_ID;
7458             else
7459                 lParam = WND_PARENT_ID;
7460         }
7461     }
7462
7463     /* Log also SetFocus(0) calls */
7464     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7465
7466     if (is_our_logged_class(hwnd))
7467     {
7468         struct recvd_message msg;
7469
7470         msg.hwnd = hwnd;
7471         msg.message = nCode;
7472         msg.flags = hook|wparam|lparam;
7473         msg.wParam = wParam;
7474         msg.lParam = lParam;
7475         msg.descr = "CBT";
7476         add_message(&msg);
7477     }
7478     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7479 }
7480
7481 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7482                                     DWORD event,
7483                                     HWND hwnd,
7484                                     LONG object_id,
7485                                     LONG child_id,
7486                                     DWORD thread_id,
7487                                     DWORD event_time)
7488 {
7489     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7490
7491     /* ignore mouse cursor events */
7492     if (object_id == OBJID_CURSOR) return;
7493
7494     if (!hwnd || is_our_logged_class(hwnd))
7495     {
7496         struct recvd_message msg;
7497
7498         msg.hwnd = hwnd;
7499         msg.message = event;
7500         msg.flags = winevent_hook|wparam|lparam;
7501         msg.wParam = object_id;
7502         msg.lParam = child_id;
7503         msg.descr = "WEH";
7504         add_message(&msg);
7505     }
7506 }
7507
7508 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7509 static const WCHAR wszAnsi[] = {'U',0};
7510
7511 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7512 {
7513     switch (uMsg)
7514     {
7515     case CB_FINDSTRINGEXACT:
7516         trace("String: %p\n", (LPCWSTR)lParam);
7517         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7518             return 1;
7519         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7520             return 0;
7521         return -1;
7522     }
7523     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7524 }
7525
7526 static const struct message WmGetTextLengthAfromW[] = {
7527     { WM_GETTEXTLENGTH, sent },
7528     { WM_GETTEXT, sent|optional },
7529     { 0 }
7530 };
7531
7532 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7533
7534 /* dummy window proc for WM_GETTEXTLENGTH test */
7535 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7536 {
7537     switch(msg)
7538     {
7539     case WM_GETTEXTLENGTH:
7540         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7541     case WM_GETTEXT:
7542         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7543         return lstrlenW( (LPWSTR)lp );
7544     default:
7545         return DefWindowProcW( hwnd, msg, wp, lp );
7546     }
7547 }
7548
7549 static void test_message_conversion(void)
7550 {
7551     static const WCHAR wszMsgConversionClass[] =
7552         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7553     WNDCLASSW cls;
7554     LRESULT lRes;
7555     HWND hwnd;
7556     WNDPROC wndproc, newproc;
7557     BOOL ret;
7558
7559     cls.style = 0;
7560     cls.lpfnWndProc = MsgConversionProcW;
7561     cls.cbClsExtra = 0;
7562     cls.cbWndExtra = 0;
7563     cls.hInstance = GetModuleHandleW(NULL);
7564     cls.hIcon = NULL;
7565     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7566     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7567     cls.lpszMenuName = NULL;
7568     cls.lpszClassName = wszMsgConversionClass;
7569     /* this call will fail on Win9x, but that doesn't matter as this test is
7570      * meaningless on those platforms */
7571     if(!RegisterClassW(&cls)) return;
7572
7573     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7574                            100, 100, 200, 200, 0, 0, 0, NULL);
7575     ok(hwnd != NULL, "Window creation failed\n");
7576
7577     /* {W, A} -> A */
7578
7579     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7580     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7581     ok(lRes == 0, "String should have been converted\n");
7582     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7583     ok(lRes == 1, "String shouldn't have been converted\n");
7584
7585     /* {W, A} -> W */
7586
7587     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7588     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7589     ok(lRes == 1, "String shouldn't have been converted\n");
7590     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7591     ok(lRes == 1, "String shouldn't have been converted\n");
7592
7593     /* Synchronous messages */
7594
7595     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7596     ok(lRes == 0, "String should have been converted\n");
7597     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7598     ok(lRes == 1, "String shouldn't have been converted\n");
7599
7600     /* Asynchronous messages */
7601
7602     SetLastError(0);
7603     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7604     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7605         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7606     SetLastError(0);
7607     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7608     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7609         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7610     SetLastError(0);
7611     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7612     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7613         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7614     SetLastError(0);
7615     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7616     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7617         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7618     SetLastError(0);
7619     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7620     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7621         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7622     SetLastError(0);
7623     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7624     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7625         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7626     SetLastError(0);
7627     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7628     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7629         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7630     SetLastError(0);
7631     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7632     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7633         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7634
7635     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7636
7637     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7638                           WS_OVERLAPPEDWINDOW,
7639                           100, 100, 200, 200, 0, 0, 0, NULL);
7640     assert(hwnd);
7641     flush_sequence();
7642     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7643     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7644     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7645         "got bad length %ld\n", lRes );
7646
7647     flush_sequence();
7648     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7649                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7650     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7651     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7652         "got bad length %ld\n", lRes );
7653
7654     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7655     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7656     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7657     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7658                                      NULL, 0, NULL, NULL ) ||
7659         broken(lRes == lstrlenW(dummy_window_text) + 37),
7660         "got bad length %ld\n", lRes );
7661
7662     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7663     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7664     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7665                                      NULL, 0, NULL, NULL ) ||
7666         broken(lRes == lstrlenW(dummy_window_text) + 37),
7667         "got bad length %ld\n", lRes );
7668
7669     ret = DestroyWindow(hwnd);
7670     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7671 }
7672
7673 struct timer_info
7674 {
7675     HWND hWnd;
7676     HANDLE handles[2];
7677     DWORD id;
7678 };
7679
7680 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7681 {
7682 }
7683
7684 #define TIMER_ID  0x19
7685
7686 static DWORD WINAPI timer_thread_proc(LPVOID x)
7687 {
7688     struct timer_info *info = x;
7689     DWORD r;
7690
7691     r = KillTimer(info->hWnd, 0x19);
7692     ok(r,"KillTimer failed in thread\n");
7693     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7694     ok(r,"SetTimer failed in thread\n");
7695     ok(r==TIMER_ID,"SetTimer id different\n");
7696     r = SetEvent(info->handles[0]);
7697     ok(r,"SetEvent failed in thread\n");
7698     return 0;
7699 }
7700
7701 static void test_timers(void)
7702 {
7703     struct timer_info info;
7704     DWORD id;
7705
7706     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7707        WS_OVERLAPPEDWINDOW ,
7708        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7709        NULL, NULL, 0);
7710
7711     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7712     ok(info.id, "SetTimer failed\n");
7713     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7714     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7715     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7716
7717     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7718
7719     WaitForSingleObject(info.handles[1], INFINITE);
7720
7721     CloseHandle(info.handles[0]);
7722     CloseHandle(info.handles[1]);
7723
7724     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7725
7726     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7727 }
7728
7729 static int count = 0;
7730 static VOID CALLBACK callback_count(
7731     HWND hwnd,
7732     UINT uMsg,
7733     UINT_PTR idEvent,
7734     DWORD dwTime
7735 )
7736 {
7737     count++;
7738 }
7739
7740 static void test_timers_no_wnd(void)
7741 {
7742     UINT_PTR id, id2;
7743     MSG msg;
7744
7745     count = 0;
7746     id = SetTimer(NULL, 0, 100, callback_count);
7747     ok(id != 0, "did not get id from SetTimer.\n");
7748     id2 = SetTimer(NULL, id, 200, callback_count);
7749     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7750     Sleep(150);
7751     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7752     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7753     Sleep(150);
7754     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7755     ok(count == 1, "did not get one count as expected (%i).\n", count);
7756     KillTimer(NULL, id);
7757     Sleep(250);
7758     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7759     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7760 }
7761
7762 /* Various win events with arbitrary parameters */
7763 static const struct message WmWinEventsSeq[] = {
7764     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7765     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7766     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7767     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7768     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7769     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7770     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7771     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7772     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7773     /* our win event hook ignores OBJID_CURSOR events */
7774     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7775     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7776     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7777     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7778     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7779     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7780     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7781     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7782     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7783     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7784     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7785     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7786     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7787     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7788     { 0 }
7789 };
7790 static const struct message WmWinEventCaretSeq[] = {
7791     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7792     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7793     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7794     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7795     { 0 }
7796 };
7797 static const struct message WmWinEventCaretSeq_2[] = {
7798     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7799     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7800     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7801     { 0 }
7802 };
7803 static const struct message WmWinEventAlertSeq[] = {
7804     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7805     { 0 }
7806 };
7807 static const struct message WmWinEventAlertSeq_2[] = {
7808     /* create window in the thread proc */
7809     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7810     /* our test event */
7811     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7812     { 0 }
7813 };
7814 static const struct message WmGlobalHookSeq_1[] = {
7815     /* create window in the thread proc */
7816     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7817     /* our test events */
7818     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7819     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7820     { 0 }
7821 };
7822 static const struct message WmGlobalHookSeq_2[] = {
7823     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7824     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7825     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7826     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7827     { 0 }
7828 };
7829
7830 static const struct message WmMouseLLHookSeq[] = {
7831     { WM_MOUSEMOVE, hook },
7832     { WM_LBUTTONUP, hook },
7833     { WM_MOUSEMOVE, hook },
7834     { 0 }
7835 };
7836
7837 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7838                                          DWORD event,
7839                                          HWND hwnd,
7840                                          LONG object_id,
7841                                          LONG child_id,
7842                                          DWORD thread_id,
7843                                          DWORD event_time)
7844 {
7845     char buf[256];
7846
7847     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7848     {
7849         if (!lstrcmpiA(buf, "TestWindowClass") ||
7850             !lstrcmpiA(buf, "static"))
7851         {
7852             struct recvd_message msg;
7853
7854             msg.hwnd = hwnd;
7855             msg.message = event;
7856             msg.flags = winevent_hook|wparam|lparam;
7857             msg.wParam = object_id;
7858             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7859             msg.descr = "WEH_2";
7860             add_message(&msg);
7861         }
7862     }
7863 }
7864
7865 static HHOOK hCBT_global_hook;
7866 static DWORD cbt_global_hook_thread_id;
7867
7868 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7869
7870     HWND hwnd;
7871     char buf[256];
7872
7873     if (nCode == HCBT_SYSCOMMAND)
7874     {
7875         struct recvd_message msg;
7876
7877         msg.hwnd = 0;
7878         msg.message = nCode;
7879         msg.flags = hook|wparam|lparam;
7880         msg.wParam = wParam;
7881         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7882         msg.descr = "CBT_2";
7883         add_message(&msg);
7884
7885         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7886     }
7887     /* WH_MOUSE_LL hook */
7888     if (nCode == HC_ACTION)
7889     {
7890         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7891
7892         /* we can't test for real mouse events */
7893         if (mhll->flags & LLMHF_INJECTED)
7894         {
7895             struct recvd_message msg;
7896
7897             memset (&msg, 0, sizeof (msg));
7898             msg.message = wParam;
7899             msg.flags = hook;
7900             msg.descr = "CBT_2";
7901             add_message(&msg);
7902         }
7903         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7904     }
7905
7906     /* Log also SetFocus(0) calls */
7907     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7908
7909     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7910     {
7911         if (!lstrcmpiA(buf, "TestWindowClass") ||
7912             !lstrcmpiA(buf, "static"))
7913         {
7914             struct recvd_message msg;
7915
7916             msg.hwnd = hwnd;
7917             msg.message = nCode;
7918             msg.flags = hook|wparam|lparam;
7919             msg.wParam = wParam;
7920             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7921             msg.descr = "CBT_2";
7922             add_message(&msg);
7923         }
7924     }
7925     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7926 }
7927
7928 static DWORD WINAPI win_event_global_thread_proc(void *param)
7929 {
7930     HWND hwnd;
7931     MSG msg;
7932     HANDLE hevent = *(HANDLE *)param;
7933
7934     assert(pNotifyWinEvent);
7935
7936     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7937     assert(hwnd);
7938     trace("created thread window %p\n", hwnd);
7939
7940     *(HWND *)param = hwnd;
7941
7942     flush_sequence();
7943     /* this event should be received only by our new hook proc,
7944      * an old one does not expect an event from another thread.
7945      */
7946     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7947     SetEvent(hevent);
7948
7949     while (GetMessage(&msg, 0, 0, 0))
7950     {
7951         TranslateMessage(&msg);
7952         DispatchMessage(&msg);
7953     }
7954     return 0;
7955 }
7956
7957 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7958 {
7959     HWND hwnd;
7960     MSG msg;
7961     HANDLE hevent = *(HANDLE *)param;
7962
7963     flush_sequence();
7964     /* these events should be received only by our new hook proc,
7965      * an old one does not expect an event from another thread.
7966      */
7967
7968     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7969     assert(hwnd);
7970     trace("created thread window %p\n", hwnd);
7971
7972     *(HWND *)param = hwnd;
7973
7974     /* Windows doesn't like when a thread plays games with the focus,
7975        that leads to all kinds of misbehaviours and failures to activate
7976        a window. So, better keep next lines commented out.
7977     SetFocus(0);
7978     SetFocus(hwnd);*/
7979
7980     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7981     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7982
7983     SetEvent(hevent);
7984
7985     while (GetMessage(&msg, 0, 0, 0))
7986     {
7987         TranslateMessage(&msg);
7988         DispatchMessage(&msg);
7989     }
7990     return 0;
7991 }
7992
7993 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7994 {
7995     HWND hwnd;
7996     MSG msg;
7997     HANDLE hevent = *(HANDLE *)param;
7998
7999     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8000     assert(hwnd);
8001     trace("created thread window %p\n", hwnd);
8002
8003     *(HWND *)param = hwnd;
8004
8005     flush_sequence();
8006
8007     /* Windows doesn't like when a thread plays games with the focus,
8008      * that leads to all kinds of misbehaviours and failures to activate
8009      * a window. So, better don't generate a mouse click message below.
8010      */
8011     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8012     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8013     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8014
8015     SetEvent(hevent);
8016     while (GetMessage(&msg, 0, 0, 0))
8017     {
8018         TranslateMessage(&msg);
8019         DispatchMessage(&msg);
8020     }
8021     return 0;
8022 }
8023
8024 static void test_winevents(void)
8025 {
8026     BOOL ret;
8027     MSG msg;
8028     HWND hwnd, hwnd2;
8029     UINT i;
8030     HANDLE hthread, hevent;
8031     DWORD tid;
8032     HWINEVENTHOOK hhook;
8033     const struct message *events = WmWinEventsSeq;
8034
8035     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8036                            WS_OVERLAPPEDWINDOW,
8037                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8038                            NULL, NULL, 0);
8039     assert(hwnd);
8040
8041     /****** start of global hook test *************/
8042     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8043     if (!hCBT_global_hook)
8044     {
8045         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8046         skip( "cannot set global hook\n" );
8047         return;
8048     }
8049
8050     hevent = CreateEventA(NULL, 0, 0, NULL);
8051     assert(hevent);
8052     hwnd2 = hevent;
8053
8054     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8055     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8056
8057     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8058
8059     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8060
8061     flush_sequence();
8062     /* this one should be received only by old hook proc */
8063     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8064     /* this one should be received only by old hook proc */
8065     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8066
8067     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8068
8069     ret = UnhookWindowsHookEx(hCBT_global_hook);
8070     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8071
8072     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8073     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8074     CloseHandle(hthread);
8075     CloseHandle(hevent);
8076     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8077     /****** end of global hook test *************/
8078
8079     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8080     {
8081         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8082         return;
8083     }
8084
8085     flush_sequence();
8086
8087     if (0)
8088     {
8089     /* this test doesn't pass under Win9x */
8090     /* win2k ignores events with hwnd == 0 */
8091     SetLastError(0xdeadbeef);
8092     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8093     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8094        GetLastError() == 0xdeadbeef, /* Win9x */
8095        "unexpected error %d\n", GetLastError());
8096     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8097     }
8098
8099     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8100         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8101
8102     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8103
8104     /****** start of event filtering test *************/
8105     hhook = pSetWinEventHook(
8106         EVENT_OBJECT_SHOW, /* 0x8002 */
8107         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8108         GetModuleHandleA(0), win_event_global_hook_proc,
8109         GetCurrentProcessId(), 0,
8110         WINEVENT_INCONTEXT);
8111     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8112
8113     hevent = CreateEventA(NULL, 0, 0, NULL);
8114     assert(hevent);
8115     hwnd2 = hevent;
8116
8117     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8118     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8119
8120     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8121
8122     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8123
8124     flush_sequence();
8125     /* this one should be received only by old hook proc */
8126     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8127     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8128     /* this one should be received only by old hook proc */
8129     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8130
8131     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8132
8133     ret = pUnhookWinEvent(hhook);
8134     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8135
8136     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8137     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8138     CloseHandle(hthread);
8139     CloseHandle(hevent);
8140     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8141     /****** end of event filtering test *************/
8142
8143     /****** start of out of context event test *************/
8144     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8145         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8146         WINEVENT_OUTOFCONTEXT);
8147     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8148
8149     hevent = CreateEventA(NULL, 0, 0, NULL);
8150     assert(hevent);
8151     hwnd2 = hevent;
8152
8153     flush_sequence();
8154
8155     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8156     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8157
8158     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8159
8160     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8161     /* process pending winevent messages */
8162     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8163     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8164
8165     flush_sequence();
8166     /* this one should be received only by old hook proc */
8167     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8168     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8169     /* this one should be received only by old hook proc */
8170     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8171
8172     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8173     /* process pending winevent messages */
8174     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8175     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8176
8177     ret = pUnhookWinEvent(hhook);
8178     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8179
8180     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8181     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8182     CloseHandle(hthread);
8183     CloseHandle(hevent);
8184     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8185     /****** end of out of context event test *************/
8186
8187     /****** start of MOUSE_LL hook test *************/
8188     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8189     /* WH_MOUSE_LL is not supported on Win9x platforms */
8190     if (!hCBT_global_hook)
8191     {
8192         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8193         goto skip_mouse_ll_hook_test;
8194     }
8195
8196     hevent = CreateEventA(NULL, 0, 0, NULL);
8197     assert(hevent);
8198     hwnd2 = hevent;
8199
8200     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8201     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8202
8203     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8204         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8205
8206     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8207     flush_sequence();
8208
8209     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8210     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8211     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8212
8213     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8214
8215     ret = UnhookWindowsHookEx(hCBT_global_hook);
8216     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8217
8218     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8219     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8220     CloseHandle(hthread);
8221     CloseHandle(hevent);
8222     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8223     /****** end of MOUSE_LL hook test *************/
8224 skip_mouse_ll_hook_test:
8225
8226     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8227 }
8228
8229 static void test_set_hook(void)
8230 {
8231     BOOL ret;
8232     HHOOK hhook;
8233     HWINEVENTHOOK hwinevent_hook;
8234
8235     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8236     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8237     UnhookWindowsHookEx(hhook);
8238
8239     if (0)
8240     {
8241     /* this test doesn't pass under Win9x: BUG! */
8242     SetLastError(0xdeadbeef);
8243     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8244     ok(!hhook, "global hook requires hModule != 0\n");
8245     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8246     }
8247
8248     SetLastError(0xdeadbeef);
8249     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8250     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8251     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8252        GetLastError() == 0xdeadbeef, /* Win9x */
8253        "unexpected error %d\n", GetLastError());
8254
8255     SetLastError(0xdeadbeef);
8256     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8257     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8258        GetLastError() == 0xdeadbeef, /* Win9x */
8259        "unexpected error %d\n", GetLastError());
8260
8261     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8262
8263     /* even process local incontext hooks require hmodule */
8264     SetLastError(0xdeadbeef);
8265     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8266         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8267     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8268     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8269        GetLastError() == 0xdeadbeef, /* Win9x */
8270        "unexpected error %d\n", GetLastError());
8271
8272     /* even thread local incontext hooks require hmodule */
8273     SetLastError(0xdeadbeef);
8274     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8275         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8276     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8277     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8278        GetLastError() == 0xdeadbeef, /* Win9x */
8279        "unexpected error %d\n", GetLastError());
8280
8281     if (0)
8282     {
8283     /* these 3 tests don't pass under Win9x */
8284     SetLastError(0xdeadbeef);
8285     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8286         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8287     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8288     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8289
8290     SetLastError(0xdeadbeef);
8291     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8292         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8293     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8294     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8295
8296     SetLastError(0xdeadbeef);
8297     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8298         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8299     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8300     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8301     }
8302
8303     SetLastError(0xdeadbeef);
8304     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8305         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8306     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8307     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8308     ret = pUnhookWinEvent(hwinevent_hook);
8309     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8310
8311 todo_wine {
8312     /* This call succeeds under win2k SP4, but fails under Wine.
8313        Does win2k test/use passed process id? */
8314     SetLastError(0xdeadbeef);
8315     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8316         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8317     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8318     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8319     ret = pUnhookWinEvent(hwinevent_hook);
8320     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8321 }
8322
8323     SetLastError(0xdeadbeef);
8324     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8325     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8326         GetLastError() == 0xdeadbeef, /* Win9x */
8327         "unexpected error %d\n", GetLastError());
8328 }
8329
8330 static const struct message ScrollWindowPaint1[] = {
8331     { WM_PAINT, sent },
8332     { WM_ERASEBKGND, sent|beginpaint },
8333     { WM_GETTEXTLENGTH, sent|optional },
8334     { WM_PAINT, sent|optional },
8335     { WM_NCPAINT, sent|beginpaint|optional },
8336     { WM_GETTEXT, sent|beginpaint|optional },
8337     { WM_GETTEXT, sent|beginpaint|optional },
8338     { WM_GETTEXT, sent|beginpaint|optional },
8339     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8340     { WM_ERASEBKGND, sent|beginpaint|optional },
8341     { 0 }
8342 };
8343
8344 static const struct message ScrollWindowPaint2[] = {
8345     { WM_PAINT, sent },
8346     { 0 }
8347 };
8348
8349 static void test_scrollwindowex(void)
8350 {
8351     HWND hwnd, hchild;
8352     RECT rect={0,0,130,130};
8353
8354     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8355             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8356             100, 100, 200, 200, 0, 0, 0, NULL);
8357     ok (hwnd != 0, "Failed to create overlapped window\n");
8358     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8359             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8360             10, 10, 150, 150, hwnd, 0, 0, NULL);
8361     ok (hchild != 0, "Failed to create child\n");
8362     UpdateWindow(hwnd);
8363     flush_events();
8364     flush_sequence();
8365
8366     /* scroll without the child window */
8367     trace("start scroll\n");
8368     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8369             SW_ERASE|SW_INVALIDATE);
8370     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8371     trace("end scroll\n");
8372     flush_sequence();
8373     flush_events();
8374     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8375     flush_events();
8376     flush_sequence();
8377
8378     /* Now without the SW_ERASE flag */
8379     trace("start scroll\n");
8380     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8381     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8382     trace("end scroll\n");
8383     flush_sequence();
8384     flush_events();
8385     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8386     flush_events();
8387     flush_sequence();
8388
8389     /* now scroll the child window as well */
8390     trace("start scroll\n");
8391     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8392             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8393     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8394     /* windows sometimes a WM_MOVE */
8395     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8396     trace("end scroll\n");
8397     flush_sequence();
8398     flush_events();
8399     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8400     flush_events();
8401     flush_sequence();
8402
8403     /* now scroll with ScrollWindow() */
8404     trace("start scroll with ScrollWindow\n");
8405     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8406     trace("end scroll\n");
8407     flush_sequence();
8408     flush_events();
8409     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8410
8411     ok(DestroyWindow(hchild), "failed to destroy window\n");
8412     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8413     flush_sequence();
8414 }
8415
8416 static const struct message destroy_window_with_children[] = {
8417     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8418     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8419     { 0x0090, sent|optional },
8420     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8421     { 0x0090, sent|optional },
8422     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8423     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8424     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8425     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8426     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8427     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8428     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8429     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8430     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8431     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8432     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8433     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8434     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8435     { 0 }
8436 };
8437
8438 static void test_DestroyWindow(void)
8439 {
8440     BOOL ret;
8441     HWND parent, child1, child2, child3, child4, test;
8442     UINT_PTR child_id = WND_CHILD_ID + 1;
8443
8444     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8445                              100, 100, 200, 200, 0, 0, 0, NULL);
8446     assert(parent != 0);
8447     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8448                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8449     assert(child1 != 0);
8450     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8451                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8452     assert(child2 != 0);
8453     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8454                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8455     assert(child3 != 0);
8456     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8457                              0, 0, 50, 50, parent, 0, 0, NULL);
8458     assert(child4 != 0);
8459
8460     /* test owner/parent of child2 */
8461     test = GetParent(child2);
8462     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8463     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8464     if(pGetAncestor) {
8465         test = pGetAncestor(child2, GA_PARENT);
8466         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8467     }
8468     test = GetWindow(child2, GW_OWNER);
8469     ok(!test, "wrong owner %p\n", test);
8470
8471     test = SetParent(child2, parent);
8472     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8473
8474     /* test owner/parent of the parent */
8475     test = GetParent(parent);
8476     ok(!test, "wrong parent %p\n", test);
8477     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8478     if(pGetAncestor) {
8479         test = pGetAncestor(parent, GA_PARENT);
8480         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8481     }
8482     test = GetWindow(parent, GW_OWNER);
8483     ok(!test, "wrong owner %p\n", test);
8484
8485     /* test owner/parent of child1 */
8486     test = GetParent(child1);
8487     ok(test == parent, "wrong parent %p\n", test);
8488     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8489     if(pGetAncestor) {
8490         test = pGetAncestor(child1, GA_PARENT);
8491         ok(test == parent, "wrong parent %p\n", test);
8492     }
8493     test = GetWindow(child1, GW_OWNER);
8494     ok(!test, "wrong owner %p\n", test);
8495
8496     /* test owner/parent of child2 */
8497     test = GetParent(child2);
8498     ok(test == parent, "wrong parent %p\n", test);
8499     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8500     if(pGetAncestor) {
8501         test = pGetAncestor(child2, GA_PARENT);
8502         ok(test == parent, "wrong parent %p\n", test);
8503     }
8504     test = GetWindow(child2, GW_OWNER);
8505     ok(!test, "wrong owner %p\n", test);
8506
8507     /* test owner/parent of child3 */
8508     test = GetParent(child3);
8509     ok(test == child1, "wrong parent %p\n", test);
8510     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8511     if(pGetAncestor) {
8512         test = pGetAncestor(child3, GA_PARENT);
8513         ok(test == child1, "wrong parent %p\n", test);
8514     }
8515     test = GetWindow(child3, GW_OWNER);
8516     ok(!test, "wrong owner %p\n", test);
8517
8518     /* test owner/parent of child4 */
8519     test = GetParent(child4);
8520     ok(test == parent, "wrong parent %p\n", test);
8521     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8522     if(pGetAncestor) {
8523         test = pGetAncestor(child4, GA_PARENT);
8524         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8525     }
8526     test = GetWindow(child4, GW_OWNER);
8527     ok(test == parent, "wrong owner %p\n", test);
8528
8529     flush_sequence();
8530
8531     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8532            parent, child1, child2, child3, child4);
8533
8534     SetCapture(child4);
8535     test = GetCapture();
8536     ok(test == child4, "wrong capture window %p\n", test);
8537
8538     test_DestroyWindow_flag = TRUE;
8539     ret = DestroyWindow(parent);
8540     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8541     test_DestroyWindow_flag = FALSE;
8542     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8543
8544     ok(!IsWindow(parent), "parent still exists\n");
8545     ok(!IsWindow(child1), "child1 still exists\n");
8546     ok(!IsWindow(child2), "child2 still exists\n");
8547     ok(!IsWindow(child3), "child3 still exists\n");
8548     ok(!IsWindow(child4), "child4 still exists\n");
8549
8550     test = GetCapture();
8551     ok(!test, "wrong capture window %p\n", test);
8552 }
8553
8554
8555 static const struct message WmDispatchPaint[] = {
8556     { WM_NCPAINT, sent },
8557     { WM_GETTEXT, sent|defwinproc|optional },
8558     { WM_GETTEXT, sent|defwinproc|optional },
8559     { WM_ERASEBKGND, sent },
8560     { 0 }
8561 };
8562
8563 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8564 {
8565     if (message == WM_PAINT) return 0;
8566     return MsgCheckProcA( hwnd, message, wParam, lParam );
8567 }
8568
8569 static void test_DispatchMessage(void)
8570 {
8571     RECT rect;
8572     MSG msg;
8573     int count;
8574     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8575                                100, 100, 200, 200, 0, 0, 0, NULL);
8576     ShowWindow( hwnd, SW_SHOW );
8577     UpdateWindow( hwnd );
8578     flush_events();
8579     flush_sequence();
8580     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8581
8582     SetRect( &rect, -5, -5, 5, 5 );
8583     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8584     count = 0;
8585     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8586     {
8587         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8588         else
8589         {
8590             flush_sequence();
8591             DispatchMessage( &msg );
8592             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8593             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8594             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8595             if (++count > 10) break;
8596         }
8597     }
8598     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8599
8600     trace("now without DispatchMessage\n");
8601     flush_sequence();
8602     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8603     count = 0;
8604     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8605     {
8606         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8607         else
8608         {
8609             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8610             flush_sequence();
8611             /* this will send WM_NCCPAINT just like DispatchMessage does */
8612             GetUpdateRgn( hwnd, hrgn, TRUE );
8613             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8614             DeleteObject( hrgn );
8615             GetClientRect( hwnd, &rect );
8616             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8617             ok( !count, "Got multiple WM_PAINTs\n" );
8618             if (++count > 10) break;
8619         }
8620     }
8621     DestroyWindow(hwnd);
8622 }
8623
8624
8625 static const struct message WmUser[] = {
8626     { WM_USER, sent },
8627     { 0 }
8628 };
8629
8630 struct sendmsg_info
8631 {
8632     HWND  hwnd;
8633     DWORD timeout;
8634     DWORD ret;
8635 };
8636
8637 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8638 {
8639     struct sendmsg_info *info = arg;
8640     SetLastError( 0xdeadbeef );
8641     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8642     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8643                         broken(GetLastError() == 0),  /* win9x */
8644                         "unexpected error %d\n", GetLastError());
8645     return 0;
8646 }
8647
8648 static void wait_for_thread( HANDLE thread )
8649 {
8650     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8651     {
8652         MSG msg;
8653         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8654     }
8655 }
8656
8657 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8658 {
8659     if (message == WM_USER) Sleep(200);
8660     return MsgCheckProcA( hwnd, message, wParam, lParam );
8661 }
8662
8663 static void test_SendMessageTimeout(void)
8664 {
8665     HANDLE thread;
8666     struct sendmsg_info info;
8667     DWORD tid;
8668     BOOL is_win9x;
8669
8670     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8671                                100, 100, 200, 200, 0, 0, 0, NULL);
8672     flush_events();
8673     flush_sequence();
8674
8675     info.timeout = 1000;
8676     info.ret = 0xdeadbeef;
8677     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8678     wait_for_thread( thread );
8679     CloseHandle( thread );
8680     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8681     ok_sequence( WmUser, "WmUser", FALSE );
8682
8683     info.timeout = 1;
8684     info.ret = 0xdeadbeef;
8685     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8686     Sleep(100);  /* SendMessageTimeout should time out here */
8687     wait_for_thread( thread );
8688     CloseHandle( thread );
8689     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8690     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8691
8692     /* 0 means infinite timeout (but not on win9x) */
8693     info.timeout = 0;
8694     info.ret = 0xdeadbeef;
8695     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8696     Sleep(100);
8697     wait_for_thread( thread );
8698     CloseHandle( thread );
8699     is_win9x = !info.ret;
8700     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8701     else ok_sequence( WmUser, "WmUser", FALSE );
8702
8703     /* timeout is treated as signed despite the prototype (but not on win9x) */
8704     info.timeout = 0x7fffffff;
8705     info.ret = 0xdeadbeef;
8706     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8707     Sleep(100);
8708     wait_for_thread( thread );
8709     CloseHandle( thread );
8710     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8711     ok_sequence( WmUser, "WmUser", FALSE );
8712
8713     info.timeout = 0x80000000;
8714     info.ret = 0xdeadbeef;
8715     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8716     Sleep(100);
8717     wait_for_thread( thread );
8718     CloseHandle( thread );
8719     if (is_win9x)
8720     {
8721         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8722         ok_sequence( WmUser, "WmUser", FALSE );
8723     }
8724     else
8725     {
8726         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8727         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8728     }
8729
8730     /* now check for timeout during message processing */
8731     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8732     info.timeout = 100;
8733     info.ret = 0xdeadbeef;
8734     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8735     wait_for_thread( thread );
8736     CloseHandle( thread );
8737     /* we should time out but still get the message */
8738     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8739     ok_sequence( WmUser, "WmUser", FALSE );
8740
8741     DestroyWindow( info.hwnd );
8742 }
8743
8744
8745 /****************** edit message test *************************/
8746 #define ID_EDIT 0x1234
8747 static const struct message sl_edit_setfocus[] =
8748 {
8749     { HCBT_SETFOCUS, hook },
8750     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8751     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8752     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8753     { WM_SETFOCUS, sent|wparam, 0 },
8754     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8755     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8756     { WM_CTLCOLOREDIT, sent|parent },
8757     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8758     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8759     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8760     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8761     { 0 }
8762 };
8763 static const struct message ml_edit_setfocus[] =
8764 {
8765     { HCBT_SETFOCUS, hook },
8766     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8767     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8768     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8769     { WM_SETFOCUS, sent|wparam, 0 },
8770     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8771     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8772     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8773     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8774     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8775     { 0 }
8776 };
8777 static const struct message sl_edit_killfocus[] =
8778 {
8779     { HCBT_SETFOCUS, hook },
8780     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8781     { WM_KILLFOCUS, sent|wparam, 0 },
8782     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8783     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8784     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8785     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8786     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8787     { 0 }
8788 };
8789 static const struct message sl_edit_lbutton_dblclk[] =
8790 {
8791     { WM_LBUTTONDBLCLK, sent },
8792     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8793     { 0 }
8794 };
8795 static const struct message sl_edit_lbutton_down[] =
8796 {
8797     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8798     { HCBT_SETFOCUS, hook },
8799     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8800     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8801     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8802     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8803     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8804     { WM_CTLCOLOREDIT, sent|parent },
8805     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8806     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8807     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8808     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8809     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8810     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8811     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8812     { WM_CTLCOLOREDIT, sent|parent|optional },
8813     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8814     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8815     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8816     { 0 }
8817 };
8818 static const struct message ml_edit_lbutton_down[] =
8819 {
8820     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8821     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8822     { HCBT_SETFOCUS, hook },
8823     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8824     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8825     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8826     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8827     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8828     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8829     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8830     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8831     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8832     { 0 }
8833 };
8834 static const struct message sl_edit_lbutton_up[] =
8835 {
8836     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8837     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8838     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8839     { WM_CAPTURECHANGED, sent|defwinproc },
8840     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8841     { 0 }
8842 };
8843 static const struct message ml_edit_lbutton_up[] =
8844 {
8845     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8846     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8847     { WM_CAPTURECHANGED, sent|defwinproc },
8848     { 0 }
8849 };
8850
8851 static WNDPROC old_edit_proc;
8852
8853 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8854 {
8855     static long defwndproc_counter = 0;
8856     LRESULT ret;
8857     struct recvd_message msg;
8858
8859     if (ignore_message( message )) return 0;
8860
8861     msg.hwnd = hwnd;
8862     msg.message = message;
8863     msg.flags = sent|wparam|lparam;
8864     if (defwndproc_counter) msg.flags |= defwinproc;
8865     msg.wParam = wParam;
8866     msg.lParam = lParam;
8867     msg.descr = "edit";
8868     add_message(&msg);
8869
8870     defwndproc_counter++;
8871     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8872     defwndproc_counter--;
8873
8874     return ret;
8875 }
8876
8877 static void subclass_edit(void)
8878 {
8879     WNDCLASSA cls;
8880
8881     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8882
8883     old_edit_proc = cls.lpfnWndProc;
8884
8885     cls.hInstance = GetModuleHandle(0);
8886     cls.lpfnWndProc = edit_hook_proc;
8887     cls.lpszClassName = "my_edit_class";
8888     UnregisterClass(cls.lpszClassName, cls.hInstance);
8889     if (!RegisterClassA(&cls)) assert(0);
8890 }
8891
8892 static void test_edit_messages(void)
8893 {
8894     HWND hwnd, parent;
8895     DWORD dlg_code;
8896
8897     subclass_edit();
8898     log_all_parent_messages++;
8899
8900     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8901                              100, 100, 200, 200, 0, 0, 0, NULL);
8902     ok (parent != 0, "Failed to create parent window\n");
8903
8904     /* test single line edit */
8905     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8906                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8907     ok(hwnd != 0, "Failed to create edit window\n");
8908
8909     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8910     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8911
8912     ShowWindow(hwnd, SW_SHOW);
8913     UpdateWindow(hwnd);
8914     SetFocus(0);
8915     flush_sequence();
8916
8917     SetFocus(hwnd);
8918     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8919
8920     SetFocus(0);
8921     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8922
8923     SetFocus(0);
8924     ReleaseCapture();
8925     flush_sequence();
8926
8927     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8928     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8929
8930     SetFocus(0);
8931     ReleaseCapture();
8932     flush_sequence();
8933
8934     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8935     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8936
8937     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8938     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8939
8940     DestroyWindow(hwnd);
8941
8942     /* test multiline edit */
8943     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8944                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8945     ok(hwnd != 0, "Failed to create edit window\n");
8946
8947     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8948     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8949        "wrong dlg_code %08x\n", dlg_code);
8950
8951     ShowWindow(hwnd, SW_SHOW);
8952     UpdateWindow(hwnd);
8953     SetFocus(0);
8954     flush_sequence();
8955
8956     SetFocus(hwnd);
8957     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8958
8959     SetFocus(0);
8960     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8961
8962     SetFocus(0);
8963     ReleaseCapture();
8964     flush_sequence();
8965
8966     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8967     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8968
8969     SetFocus(0);
8970     ReleaseCapture();
8971     flush_sequence();
8972
8973     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8974     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8975
8976     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8977     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8978
8979     DestroyWindow(hwnd);
8980     DestroyWindow(parent);
8981
8982     log_all_parent_messages--;
8983 }
8984
8985 /**************************** End of Edit test ******************************/
8986
8987 static const struct message WmKeyDownSkippedSeq[] =
8988 {
8989     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8990     { 0 }
8991 };
8992 static const struct message WmKeyDownWasDownSkippedSeq[] =
8993 {
8994     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
8995     { 0 }
8996 };
8997 static const struct message WmKeyUpSkippedSeq[] =
8998 {
8999     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9000     { 0 }
9001 };
9002 static const struct message WmUserKeyUpSkippedSeq[] =
9003 {
9004     { WM_USER, sent },
9005     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9006     { 0 }
9007 };
9008
9009 #define EV_STOP 0
9010 #define EV_SENDMSG 1
9011 #define EV_ACK 2
9012
9013 struct peekmsg_info
9014 {
9015     HWND  hwnd;
9016     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9017 };
9018
9019 static DWORD CALLBACK send_msg_thread_2(void *param)
9020 {
9021     DWORD ret;
9022     struct peekmsg_info *info = param;
9023
9024     trace("thread: looping\n");
9025     SetEvent(info->hevent[EV_ACK]);
9026
9027     while (1)
9028     {
9029         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9030
9031         switch (ret)
9032         {
9033         case WAIT_OBJECT_0 + EV_STOP:
9034             trace("thread: exiting\n");
9035             return 0;
9036
9037         case WAIT_OBJECT_0 + EV_SENDMSG:
9038             trace("thread: sending message\n");
9039             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
9040                 "SendNotifyMessageA failed error %u\n", GetLastError());
9041             SetEvent(info->hevent[EV_ACK]);
9042             break;
9043
9044         default:
9045             trace("unexpected return: %04x\n", ret);
9046             assert(0);
9047             break;
9048         }
9049     }
9050     return 0;
9051 }
9052
9053 static void test_PeekMessage(void)
9054 {
9055     MSG msg;
9056     HANDLE hthread;
9057     DWORD tid, qstatus;
9058     UINT qs_all_input = QS_ALLINPUT;
9059     UINT qs_input = QS_INPUT;
9060     BOOL ret;
9061     struct peekmsg_info info;
9062
9063     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9064                               100, 100, 200, 200, 0, 0, 0, NULL);
9065     assert(info.hwnd);
9066     ShowWindow(info.hwnd, SW_SHOW);
9067     UpdateWindow(info.hwnd);
9068     SetFocus(info.hwnd);
9069
9070     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9071     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9072     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9073
9074     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9075     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9076
9077     flush_events();
9078     flush_sequence();
9079
9080     SetLastError(0xdeadbeef);
9081     qstatus = GetQueueStatus(qs_all_input);
9082     if (GetLastError() == ERROR_INVALID_FLAGS)
9083     {
9084         trace("QS_RAWINPUT not supported on this platform\n");
9085         qs_all_input &= ~QS_RAWINPUT;
9086         qs_input &= ~QS_RAWINPUT;
9087     }
9088     if (qstatus & QS_POSTMESSAGE)
9089     {
9090         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9091         qstatus = GetQueueStatus(qs_all_input);
9092     }
9093     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9094
9095     trace("signalling to send message\n");
9096     SetEvent(info.hevent[EV_SENDMSG]);
9097     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9098
9099     /* pass invalid QS_xxxx flags */
9100     SetLastError(0xdeadbeef);
9101     qstatus = GetQueueStatus(0xffffffff);
9102     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9103     if (!qstatus)
9104     {
9105         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9106         qstatus = GetQueueStatus(qs_all_input);
9107     }
9108     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9109     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9110        "wrong qstatus %08x\n", qstatus);
9111
9112     msg.message = 0;
9113     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9114     ok(!ret,
9115        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9116         msg.message);
9117     ok_sequence(WmUser, "WmUser", FALSE);
9118
9119     qstatus = GetQueueStatus(qs_all_input);
9120     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9121
9122     keybd_event('N', 0, 0, 0);
9123     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9124     qstatus = GetQueueStatus(qs_all_input);
9125     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9126     {
9127         skip( "queuing key events not supported\n" );
9128         goto done;
9129     }
9130     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
9131        "wrong qstatus %08x\n", qstatus);
9132
9133     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9134     qstatus = GetQueueStatus(qs_all_input);
9135     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9136        "wrong qstatus %08x\n", qstatus);
9137
9138     InvalidateRect(info.hwnd, NULL, FALSE);
9139     qstatus = GetQueueStatus(qs_all_input);
9140     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9141        "wrong qstatus %08x\n", qstatus);
9142
9143     trace("signalling to send message\n");
9144     SetEvent(info.hevent[EV_SENDMSG]);
9145     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9146
9147     qstatus = GetQueueStatus(qs_all_input);
9148     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9149        "wrong qstatus %08x\n", qstatus);
9150
9151     msg.message = 0;
9152     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9153     if (ret && msg.message == WM_CHAR)
9154     {
9155         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9156         goto done;
9157     }
9158     ok(!ret,
9159        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9160         msg.message);
9161     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9162     {
9163         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9164         goto done;
9165     }
9166     ok_sequence(WmUser, "WmUser", FALSE);
9167
9168     qstatus = GetQueueStatus(qs_all_input);
9169     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9170        "wrong qstatus %08x\n", qstatus);
9171
9172     trace("signalling to send message\n");
9173     SetEvent(info.hevent[EV_SENDMSG]);
9174     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9175
9176     qstatus = GetQueueStatus(qs_all_input);
9177     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9178        "wrong qstatus %08x\n", qstatus);
9179
9180     msg.message = 0;
9181     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9182     ok(!ret,
9183        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9184         msg.message);
9185     ok_sequence(WmUser, "WmUser", FALSE);
9186
9187     qstatus = GetQueueStatus(qs_all_input);
9188     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9189        "wrong qstatus %08x\n", qstatus);
9190
9191     msg.message = 0;
9192     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9193     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9194        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9195        ret, msg.message, msg.wParam);
9196     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9197
9198     qstatus = GetQueueStatus(qs_all_input);
9199     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9200        "wrong qstatus %08x\n", qstatus);
9201
9202     msg.message = 0;
9203     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9204     ok(!ret,
9205        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9206         msg.message);
9207     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9208
9209     qstatus = GetQueueStatus(qs_all_input);
9210     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9211        "wrong qstatus %08x\n", qstatus);
9212
9213     msg.message = 0;
9214     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9215     ok(ret && msg.message == WM_PAINT,
9216        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9217     DispatchMessageA(&msg);
9218     ok_sequence(WmPaint, "WmPaint", FALSE);
9219
9220     qstatus = GetQueueStatus(qs_all_input);
9221     ok(qstatus == MAKELONG(0, QS_KEY),
9222        "wrong qstatus %08x\n", qstatus);
9223
9224     msg.message = 0;
9225     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9226     ok(!ret,
9227        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9228         msg.message);
9229     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9230
9231     qstatus = GetQueueStatus(qs_all_input);
9232     ok(qstatus == MAKELONG(0, QS_KEY),
9233        "wrong qstatus %08x\n", qstatus);
9234
9235     trace("signalling to send message\n");
9236     SetEvent(info.hevent[EV_SENDMSG]);
9237     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9238
9239     qstatus = GetQueueStatus(qs_all_input);
9240     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9241        "wrong qstatus %08x\n", qstatus);
9242
9243     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9244
9245     qstatus = GetQueueStatus(qs_all_input);
9246     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9247        "wrong qstatus %08x\n", qstatus);
9248
9249     msg.message = 0;
9250     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9251     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9252        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9253        ret, msg.message, msg.wParam);
9254     ok_sequence(WmUser, "WmUser", FALSE);
9255
9256     qstatus = GetQueueStatus(qs_all_input);
9257     ok(qstatus == MAKELONG(0, QS_KEY),
9258        "wrong qstatus %08x\n", qstatus);
9259
9260     msg.message = 0;
9261     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9262     ok(!ret,
9263        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9264         msg.message);
9265     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9266
9267     qstatus = GetQueueStatus(qs_all_input);
9268     ok(qstatus == MAKELONG(0, QS_KEY),
9269        "wrong qstatus %08x\n", qstatus);
9270
9271     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9272
9273     qstatus = GetQueueStatus(qs_all_input);
9274     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9275        "wrong qstatus %08x\n", qstatus);
9276
9277     trace("signalling to send message\n");
9278     SetEvent(info.hevent[EV_SENDMSG]);
9279     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9280
9281     qstatus = GetQueueStatus(qs_all_input);
9282     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9283        "wrong qstatus %08x\n", qstatus);
9284
9285     msg.message = 0;
9286     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9287     ok(!ret,
9288        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9289         msg.message);
9290     ok_sequence(WmUser, "WmUser", FALSE);
9291
9292     qstatus = GetQueueStatus(qs_all_input);
9293     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9294        "wrong qstatus %08x\n", qstatus);
9295
9296     msg.message = 0;
9297     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9298         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9299     else /* workaround for a missing QS_RAWINPUT support */
9300         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9301     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9302        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9303        ret, msg.message, msg.wParam);
9304     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9305
9306     qstatus = GetQueueStatus(qs_all_input);
9307     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9308        "wrong qstatus %08x\n", qstatus);
9309
9310     msg.message = 0;
9311     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9312         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9313     else /* workaround for a missing QS_RAWINPUT support */
9314         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9315     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9316        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9317        ret, msg.message, msg.wParam);
9318     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9319
9320     qstatus = GetQueueStatus(qs_all_input);
9321     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9322        "wrong qstatus %08x\n", qstatus);
9323
9324     msg.message = 0;
9325     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9326     ok(!ret,
9327        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9328         msg.message);
9329     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9330
9331     qstatus = GetQueueStatus(qs_all_input);
9332     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9333        "wrong qstatus %08x\n", qstatus);
9334
9335     msg.message = 0;
9336     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9337     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9338        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9339        ret, msg.message, msg.wParam);
9340     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9341
9342     qstatus = GetQueueStatus(qs_all_input);
9343     ok(qstatus == 0,
9344        "wrong qstatus %08x\n", qstatus);
9345
9346     msg.message = 0;
9347     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9348     ok(!ret,
9349        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9350         msg.message);
9351     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9352
9353     qstatus = GetQueueStatus(qs_all_input);
9354     ok(qstatus == 0,
9355        "wrong qstatus %08x\n", qstatus);
9356
9357     /* test whether presence of the quit flag in the queue affects
9358      * the queue state
9359      */
9360     PostQuitMessage(0x1234abcd);
9361
9362     qstatus = GetQueueStatus(qs_all_input);
9363     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9364        "wrong qstatus %08x\n", qstatus);
9365
9366     PostMessageA(info.hwnd, WM_USER, 0, 0);
9367
9368     qstatus = GetQueueStatus(qs_all_input);
9369     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9370        "wrong qstatus %08x\n", qstatus);
9371
9372     msg.message = 0;
9373     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9374     ok(ret && msg.message == WM_USER,
9375        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9376     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9377
9378     qstatus = GetQueueStatus(qs_all_input);
9379     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9380        "wrong qstatus %08x\n", qstatus);
9381
9382     msg.message = 0;
9383     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9384     ok(ret && msg.message == WM_QUIT,
9385        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9386     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9387     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9388     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9389
9390     qstatus = GetQueueStatus(qs_all_input);
9391 todo_wine {
9392     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9393        "wrong qstatus %08x\n", qstatus);
9394 }
9395
9396     msg.message = 0;
9397     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9398     ok(!ret,
9399        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9400         msg.message);
9401     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9402
9403     qstatus = GetQueueStatus(qs_all_input);
9404     ok(qstatus == 0,
9405        "wrong qstatus %08x\n", qstatus);
9406
9407     /* some GetMessage tests */
9408
9409     keybd_event('N', 0, 0, 0);
9410     qstatus = GetQueueStatus(qs_all_input);
9411     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9412
9413     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9414     qstatus = GetQueueStatus(qs_all_input);
9415     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9416
9417     if (qstatus)
9418     {
9419         ret = GetMessageA( &msg, 0, 0, 0 );
9420         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9421            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9422            ret, msg.message, msg.wParam);
9423         qstatus = GetQueueStatus(qs_all_input);
9424         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9425     }
9426
9427     if (qstatus)
9428     {
9429         ret = GetMessageA( &msg, 0, 0, 0 );
9430         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9431            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9432            ret, msg.message, msg.wParam);
9433         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9434         qstatus = GetQueueStatus(qs_all_input);
9435         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9436     }
9437
9438     keybd_event('N', 0, 0, 0);
9439     qstatus = GetQueueStatus(qs_all_input);
9440     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9441
9442     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9443     qstatus = GetQueueStatus(qs_all_input);
9444     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9445
9446     if (qstatus & (QS_KEY << 16))
9447     {
9448         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9449         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9450            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9451            ret, msg.message, msg.wParam);
9452         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9453         qstatus = GetQueueStatus(qs_all_input);
9454         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9455     }
9456
9457     if (qstatus)
9458     {
9459         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9460         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9461            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9462            ret, msg.message, msg.wParam);
9463         qstatus = GetQueueStatus(qs_all_input);
9464         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9465     }
9466
9467     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9468     qstatus = GetQueueStatus(qs_all_input);
9469     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9470
9471     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9472     qstatus = GetQueueStatus(qs_all_input);
9473     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9474
9475     trace("signalling to send message\n");
9476     SetEvent(info.hevent[EV_SENDMSG]);
9477     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9478     qstatus = GetQueueStatus(qs_all_input);
9479     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9480        "wrong qstatus %08x\n", qstatus);
9481
9482     if (qstatus & (QS_KEY << 16))
9483     {
9484         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9485         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9486            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9487            ret, msg.message, msg.wParam);
9488         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9489         qstatus = GetQueueStatus(qs_all_input);
9490         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9491     }
9492
9493     if (qstatus)
9494     {
9495         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9496         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9497            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9498            ret, msg.message, msg.wParam);
9499         qstatus = GetQueueStatus(qs_all_input);
9500         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9501     }
9502 done:
9503     trace("signalling to exit\n");
9504     SetEvent(info.hevent[EV_STOP]);
9505
9506     WaitForSingleObject(hthread, INFINITE);
9507
9508     CloseHandle(hthread);
9509     CloseHandle(info.hevent[0]);
9510     CloseHandle(info.hevent[1]);
9511     CloseHandle(info.hevent[2]);
9512
9513     DestroyWindow(info.hwnd);
9514 }
9515
9516 static void wait_move_event(HWND hwnd, int x, int y)
9517 {
9518     MSG msg;
9519     DWORD time;
9520     BOOL  ret;
9521     int go = 0;
9522
9523     time = GetTickCount();
9524     while (GetTickCount() - time < 200 && !go) {
9525         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9526         go  = ret && msg.pt.x > x && msg.pt.y > y;
9527         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9528     }
9529 }
9530
9531 #define STEP 5
9532 static void test_PeekMessage2(void)
9533 {
9534     HWND hwnd;
9535     BOOL ret;
9536     MSG msg;
9537     UINT message;
9538     DWORD time1, time2, time3;
9539     int x1, y1, x2, y2, x3, y3;
9540     POINT pos;
9541
9542     time1 = time2 = time3 = 0;
9543     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9544
9545     /* Initialise window and make sure it is ready for events */
9546     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9547                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9548     assert(hwnd);
9549     trace("Window for test_PeekMessage2 %p\n", hwnd);
9550     ShowWindow(hwnd, SW_SHOW);
9551     UpdateWindow(hwnd);
9552     SetFocus(hwnd);
9553     GetCursorPos(&pos);
9554     SetCursorPos(100, 100);
9555     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9556     flush_events();
9557
9558     /* Do initial mousemove, wait until we can see it
9559        and then do our test peek with PM_NOREMOVE. */
9560     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9561     wait_move_event(hwnd, 100-STEP, 100-STEP);
9562
9563     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9564     if (!ret)
9565     {
9566         skip( "queuing mouse events not supported\n" );
9567         goto done;
9568     }
9569     else
9570     {
9571         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9572         message = msg.message;
9573         time1 = msg.time;
9574         x1 = msg.pt.x;
9575         y1 = msg.pt.y;
9576         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9577     }
9578
9579     /* Allow time to advance a bit, and then simulate the user moving their
9580      * mouse around. After that we peek again with PM_NOREMOVE.
9581      * Although the previous mousemove message was never removed, the
9582      * mousemove we now peek should reflect the recent mouse movements
9583      * because the input queue will merge the move events. */
9584     Sleep(100);
9585     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9586     wait_move_event(hwnd, x1, y1);
9587
9588     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9589     ok(ret, "no message available\n");
9590     if (ret) {
9591         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9592         message = msg.message;
9593         time2 = msg.time;
9594         x2 = msg.pt.x;
9595         y2 = msg.pt.y;
9596         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9597         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9598         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9599     }
9600
9601     /* Have another go, to drive the point home */
9602     Sleep(100);
9603     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9604     wait_move_event(hwnd, x2, y2);
9605
9606     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9607     ok(ret, "no message available\n");
9608     if (ret) {
9609         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9610         message = msg.message;
9611         time3 = msg.time;
9612         x3 = msg.pt.x;
9613         y3 = msg.pt.y;
9614         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9615         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9616         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9617     }
9618
9619 done:
9620     DestroyWindow(hwnd);
9621     SetCursorPos(pos.x, pos.y);
9622     flush_events();
9623 }
9624
9625 static void test_quit_message(void)
9626 {
9627     MSG msg;
9628     BOOL ret;
9629
9630     /* test using PostQuitMessage */
9631     flush_events();
9632     PostQuitMessage(0xbeef);
9633
9634     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9635     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9636     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9637     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9638
9639     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9640     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9641
9642     ret = GetMessage(&msg, NULL, 0, 0);
9643     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9644     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9645
9646     /* note: WM_QUIT message received after WM_USER message */
9647     ret = GetMessage(&msg, NULL, 0, 0);
9648     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9649     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9650     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9651
9652     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9653     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9654
9655     /* now test with PostThreadMessage - different behaviour! */
9656     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9657
9658     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9659     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9660     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9661     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9662
9663     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9664     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9665
9666     /* note: we receive the WM_QUIT message first this time */
9667     ret = GetMessage(&msg, NULL, 0, 0);
9668     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9669     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9670     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9671
9672     ret = GetMessage(&msg, NULL, 0, 0);
9673     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9674     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9675 }
9676
9677 static const struct message WmMouseHoverSeq[] = {
9678     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9679     { WM_MOUSEACTIVATE, sent|optional },
9680     { WM_TIMER, sent|optional }, /* XP sends it */
9681     { WM_SYSTIMER, sent },
9682     { WM_MOUSEHOVER, sent|wparam, 0 },
9683     { 0 }
9684 };
9685
9686 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9687 {
9688     MSG msg;
9689     DWORD start_ticks, end_ticks;
9690
9691     start_ticks = GetTickCount();
9692     /* add some deviation (50%) to cover not expected delays */
9693     start_ticks += timeout / 2;
9694
9695     do
9696     {
9697         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9698         {
9699             /* Timer proc messages are not dispatched to the window proc,
9700              * and therefore not logged.
9701              */
9702             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9703             {
9704                 struct recvd_message s_msg;
9705
9706                 s_msg.hwnd = msg.hwnd;
9707                 s_msg.message = msg.message;
9708                 s_msg.flags = sent|wparam|lparam;
9709                 s_msg.wParam = msg.wParam;
9710                 s_msg.lParam = msg.lParam;
9711                 s_msg.descr = "msg_loop";
9712                 add_message(&s_msg);
9713             }
9714             DispatchMessage(&msg);
9715         }
9716
9717         end_ticks = GetTickCount();
9718
9719         /* inject WM_MOUSEMOVE to see how it changes tracking */
9720         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9721         {
9722             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9723             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9724
9725             inject_mouse_move = FALSE;
9726         }
9727     } while (start_ticks + timeout >= end_ticks);
9728 }
9729
9730 static void test_TrackMouseEvent(void)
9731 {
9732     TRACKMOUSEEVENT tme;
9733     BOOL ret;
9734     HWND hwnd, hchild;
9735     RECT rc_parent, rc_child;
9736     UINT default_hover_time, hover_width = 0, hover_height = 0;
9737
9738 #define track_hover(track_hwnd, track_hover_time) \
9739     tme.cbSize = sizeof(tme); \
9740     tme.dwFlags = TME_HOVER; \
9741     tme.hwndTrack = track_hwnd; \
9742     tme.dwHoverTime = track_hover_time; \
9743     SetLastError(0xdeadbeef); \
9744     ret = pTrackMouseEvent(&tme); \
9745     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9746
9747 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9748     tme.cbSize = sizeof(tme); \
9749     tme.dwFlags = TME_QUERY; \
9750     tme.hwndTrack = (HWND)0xdeadbeef; \
9751     tme.dwHoverTime = 0xdeadbeef; \
9752     SetLastError(0xdeadbeef); \
9753     ret = pTrackMouseEvent(&tme); \
9754     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9755     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9756     ok(tme.dwFlags == (expected_track_flags), \
9757        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9758     ok(tme.hwndTrack == (expected_track_hwnd), \
9759        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9760     ok(tme.dwHoverTime == (expected_hover_time), \
9761        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9762
9763 #define track_hover_cancel(track_hwnd) \
9764     tme.cbSize = sizeof(tme); \
9765     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9766     tme.hwndTrack = track_hwnd; \
9767     tme.dwHoverTime = 0xdeadbeef; \
9768     SetLastError(0xdeadbeef); \
9769     ret = pTrackMouseEvent(&tme); \
9770     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9771
9772     default_hover_time = 0xdeadbeef;
9773     SetLastError(0xdeadbeef);
9774     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9775     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9776        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9777     if (!ret) default_hover_time = 400;
9778     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9779
9780     SetLastError(0xdeadbeef);
9781     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9782     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9783        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9784     if (!ret) hover_width = 4;
9785     SetLastError(0xdeadbeef);
9786     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9787     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9788        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9789     if (!ret) hover_height = 4;
9790     trace("hover rect is %u x %d\n", hover_width, hover_height);
9791
9792     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9793                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9794                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9795                           NULL, NULL, 0);
9796     assert(hwnd);
9797
9798     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9799                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9800                           50, 50, 200, 200, hwnd,
9801                           NULL, NULL, 0);
9802     assert(hchild);
9803
9804     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9805     flush_events();
9806     flush_sequence();
9807
9808     tme.cbSize = 0;
9809     tme.dwFlags = TME_QUERY;
9810     tme.hwndTrack = (HWND)0xdeadbeef;
9811     tme.dwHoverTime = 0xdeadbeef;
9812     SetLastError(0xdeadbeef);
9813     ret = pTrackMouseEvent(&tme);
9814     ok(!ret, "TrackMouseEvent should fail\n");
9815     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9816        "not expected error %u\n", GetLastError());
9817
9818     tme.cbSize = sizeof(tme);
9819     tme.dwFlags = TME_HOVER;
9820     tme.hwndTrack = (HWND)0xdeadbeef;
9821     tme.dwHoverTime = 0xdeadbeef;
9822     SetLastError(0xdeadbeef);
9823     ret = pTrackMouseEvent(&tme);
9824     ok(!ret, "TrackMouseEvent should fail\n");
9825     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9826        "not expected error %u\n", GetLastError());
9827
9828     tme.cbSize = sizeof(tme);
9829     tme.dwFlags = TME_HOVER | TME_CANCEL;
9830     tme.hwndTrack = (HWND)0xdeadbeef;
9831     tme.dwHoverTime = 0xdeadbeef;
9832     SetLastError(0xdeadbeef);
9833     ret = pTrackMouseEvent(&tme);
9834     ok(!ret, "TrackMouseEvent should fail\n");
9835     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9836        "not expected error %u\n", GetLastError());
9837
9838     GetWindowRect(hwnd, &rc_parent);
9839     GetWindowRect(hchild, &rc_child);
9840     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9841
9842     /* Process messages so that the system updates its internal current
9843      * window and hittest, otherwise TrackMouseEvent calls don't have any
9844      * effect.
9845      */
9846     flush_events();
9847     flush_sequence();
9848
9849     track_query(0, NULL, 0);
9850     track_hover(hchild, 0);
9851     track_query(0, NULL, 0);
9852
9853     flush_events();
9854     flush_sequence();
9855
9856     track_hover(hwnd, 0);
9857     tme.cbSize = sizeof(tme);
9858     tme.dwFlags = TME_QUERY;
9859     tme.hwndTrack = (HWND)0xdeadbeef;
9860     tme.dwHoverTime = 0xdeadbeef;
9861     SetLastError(0xdeadbeef);
9862     ret = pTrackMouseEvent(&tme);
9863     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
9864     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
9865     if (!tme.dwFlags)
9866     {
9867         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
9868         DestroyWindow( hwnd );
9869         return;
9870     }
9871     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
9872     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
9873     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
9874        tme.dwHoverTime, default_hover_time);
9875
9876     pump_msg_loop_timeout(default_hover_time, FALSE);
9877     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9878
9879     track_query(0, NULL, 0);
9880
9881     track_hover(hwnd, HOVER_DEFAULT);
9882     track_query(TME_HOVER, hwnd, default_hover_time);
9883
9884     Sleep(default_hover_time / 2);
9885     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9886     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9887
9888     track_query(TME_HOVER, hwnd, default_hover_time);
9889
9890     pump_msg_loop_timeout(default_hover_time, FALSE);
9891     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9892
9893     track_query(0, NULL, 0);
9894
9895     track_hover(hwnd, HOVER_DEFAULT);
9896     track_query(TME_HOVER, hwnd, default_hover_time);
9897
9898     pump_msg_loop_timeout(default_hover_time, TRUE);
9899     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9900
9901     track_query(0, NULL, 0);
9902
9903     track_hover(hwnd, HOVER_DEFAULT);
9904     track_query(TME_HOVER, hwnd, default_hover_time);
9905     track_hover_cancel(hwnd);
9906
9907     DestroyWindow(hwnd);
9908
9909 #undef track_hover
9910 #undef track_query
9911 #undef track_hover_cancel
9912 }
9913
9914
9915 static const struct message WmSetWindowRgn[] = {
9916     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9917     { WM_NCCALCSIZE, sent|wparam, 1 },
9918     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9919     { WM_GETTEXT, sent|defwinproc|optional },
9920     { WM_ERASEBKGND, sent|optional },
9921     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9922     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9923     { 0 }
9924 };
9925
9926 static const struct message WmSetWindowRgn_no_redraw[] = {
9927     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9928     { WM_NCCALCSIZE, sent|wparam, 1 },
9929     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9930     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9931     { 0 }
9932 };
9933
9934 static const struct message WmSetWindowRgn_clear[] = {
9935     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
9936     { WM_NCCALCSIZE, sent|wparam, 1 },
9937     { WM_NCPAINT, sent|optional },
9938     { WM_GETTEXT, sent|defwinproc|optional },
9939     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9940     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9941     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9942     { WM_NCPAINT, sent|optional },
9943     { WM_GETTEXT, sent|defwinproc|optional },
9944     { WM_ERASEBKGND, sent|optional },
9945     { WM_WINDOWPOSCHANGING, sent|optional },
9946     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9947     { WM_NCPAINT, sent|optional },
9948     { WM_GETTEXT, sent|defwinproc|optional },
9949     { WM_ERASEBKGND, sent|optional },
9950     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9951     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9952     { WM_NCPAINT, sent|optional },
9953     { WM_GETTEXT, sent|defwinproc|optional },
9954     { WM_ERASEBKGND, sent|optional },
9955     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9956     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9957     { 0 }
9958 };
9959
9960 static void test_SetWindowRgn(void)
9961 {
9962     HRGN hrgn;
9963     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9964                                 100, 100, 200, 200, 0, 0, 0, NULL);
9965     ok( hwnd != 0, "Failed to create overlapped window\n" );
9966
9967     ShowWindow( hwnd, SW_SHOW );
9968     UpdateWindow( hwnd );
9969     flush_events();
9970     flush_sequence();
9971
9972     trace("testing SetWindowRgn\n");
9973     hrgn = CreateRectRgn( 0, 0, 150, 150 );
9974     SetWindowRgn( hwnd, hrgn, TRUE );
9975     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9976
9977     hrgn = CreateRectRgn( 30, 30, 160, 160 );
9978     SetWindowRgn( hwnd, hrgn, FALSE );
9979     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9980
9981     hrgn = CreateRectRgn( 0, 0, 180, 180 );
9982     SetWindowRgn( hwnd, hrgn, TRUE );
9983     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9984
9985     SetWindowRgn( hwnd, 0, TRUE );
9986     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9987
9988     DestroyWindow( hwnd );
9989 }
9990
9991 /*************************** ShowWindow() test ******************************/
9992 static const struct message WmShowNormal[] = {
9993     { WM_SHOWWINDOW, sent|wparam, 1 },
9994     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9995     { HCBT_ACTIVATE, hook },
9996     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9997     { HCBT_SETFOCUS, hook },
9998     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9999     { 0 }
10000 };
10001 static const struct message WmShow[] = {
10002     { WM_SHOWWINDOW, sent|wparam, 1 },
10003     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10004     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10005     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10006     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10007     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10008     { 0 }
10009 };
10010 static const struct message WmShowNoActivate_1[] = {
10011     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10012     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10013     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10014     { WM_MOVE, sent|defwinproc|optional },
10015     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10016     { 0 }
10017 };
10018 static const struct message WmShowNoActivate_2[] = {
10019     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10020     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10021     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10022     { WM_MOVE, sent|defwinproc },
10023     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10024     { HCBT_SETFOCUS, hook|optional },
10025     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10026     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10027     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10028     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10029     { 0 }
10030 };
10031 static const struct message WmShowNA_1[] = {
10032     { WM_SHOWWINDOW, sent|wparam, 1 },
10033     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10034     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10035     { 0 }
10036 };
10037 static const struct message WmShowNA_2[] = {
10038     { WM_SHOWWINDOW, sent|wparam, 1 },
10039     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10040     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10041     { 0 }
10042 };
10043 static const struct message WmRestore_1[] = {
10044     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10045     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10046     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10047     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10048     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10049     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10050     { WM_MOVE, sent|defwinproc },
10051     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10052     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10053     { 0 }
10054 };
10055 static const struct message WmRestore_2[] = {
10056     { WM_SHOWWINDOW, sent|wparam, 1 },
10057     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10058     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10059     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10060     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10061     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10062     { 0 }
10063 };
10064 static const struct message WmRestore_3[] = {
10065     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10066     { WM_GETMINMAXINFO, sent },
10067     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10068     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10069     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10070     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10071     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10072     { WM_MOVE, sent|defwinproc },
10073     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10074     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10075     { 0 }
10076 };
10077 static const struct message WmRestore_4[] = {
10078     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10079     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10080     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10081     { WM_MOVE, sent|defwinproc|optional },
10082     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10083     { 0 }
10084 };
10085 static const struct message WmRestore_5[] = {
10086     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10087     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10088     { HCBT_ACTIVATE, hook|optional },
10089     { HCBT_SETFOCUS, hook|optional },
10090     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10091     { WM_MOVE, sent|defwinproc|optional },
10092     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10093     { 0 }
10094 };
10095 static const struct message WmHide_1[] = {
10096     { WM_SHOWWINDOW, sent|wparam, 0 },
10097     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10098     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10099     { HCBT_ACTIVATE, hook|optional },
10100     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10101     { 0 }
10102 };
10103 static const struct message WmHide_2[] = {
10104     { WM_SHOWWINDOW, sent|wparam, 0 },
10105     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10106     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10107     { HCBT_ACTIVATE, hook|optional },
10108     { 0 }
10109 };
10110 static const struct message WmHide_3[] = {
10111     { WM_SHOWWINDOW, sent|wparam, 0 },
10112     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10113     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10114     { HCBT_SETFOCUS, hook|optional },
10115     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10116     { 0 }
10117 };
10118 static const struct message WmShowMinimized_1[] = {
10119     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10120     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10121     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10122     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10123     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10124     { WM_MOVE, sent|defwinproc },
10125     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10126     { 0 }
10127 };
10128 static const struct message WmMinimize_1[] = {
10129     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10130     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10131     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10132     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10133     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10134     { WM_MOVE, sent|defwinproc },
10135     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10136     { 0 }
10137 };
10138 static const struct message WmMinimize_2[] = {
10139     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10140     { HCBT_SETFOCUS, hook|optional },
10141     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10142     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10143     { WM_MOVE, sent|defwinproc },
10144     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10145     { 0 }
10146 };
10147 static const struct message WmMinimize_3[] = {
10148     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10149     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10150     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10151     { WM_MOVE, sent|defwinproc },
10152     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10153     { 0 }
10154 };
10155 static const struct message WmShowMinNoActivate[] = {
10156     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10157     { WM_WINDOWPOSCHANGING, sent },
10158     { WM_WINDOWPOSCHANGED, sent },
10159     { WM_MOVE, sent|defwinproc|optional },
10160     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MINIMIZED },
10161     { 0 }
10162 };
10163 static const struct message WmMinMax_1[] = {
10164     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10165     { 0 }
10166 };
10167 static const struct message WmMinMax_2[] = {
10168     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10169     { WM_GETMINMAXINFO, sent|optional },
10170     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10171     { HCBT_ACTIVATE, hook|optional },
10172     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10173     { HCBT_SETFOCUS, hook|optional },
10174     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10175     { WM_MOVE, sent|defwinproc|optional },
10176     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10177     { HCBT_SETFOCUS, hook|optional },
10178     { 0 }
10179 };
10180 static const struct message WmMinMax_3[] = {
10181     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10182     { HCBT_SETFOCUS, hook|optional },
10183     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10184     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10185     { WM_MOVE, sent|defwinproc|optional },
10186     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MINIMIZED },
10187     { 0 }
10188 };
10189 static const struct message WmMinMax_4[] = {
10190     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10191     { 0 }
10192 };
10193 static const struct message WmShowMaximized_1[] = {
10194     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10195     { WM_GETMINMAXINFO, sent },
10196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10197     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10198     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10199     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10200     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10201     { WM_MOVE, sent|defwinproc },
10202     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10203     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10204     { 0 }
10205 };
10206 static const struct message WmShowMaximized_2[] = {
10207     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10208     { WM_GETMINMAXINFO, sent },
10209     { WM_WINDOWPOSCHANGING, sent|optional },
10210     { HCBT_ACTIVATE, hook|optional },
10211     { WM_WINDOWPOSCHANGED, sent|optional },
10212     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10213     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10214     { WM_WINDOWPOSCHANGING, sent|optional },
10215     { HCBT_SETFOCUS, hook|optional },
10216     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10217     { WM_MOVE, sent|defwinproc },
10218     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10219     { HCBT_SETFOCUS, hook|optional },
10220     { 0 }
10221 };
10222 static const struct message WmShowMaximized_3[] = {
10223     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10224     { WM_GETMINMAXINFO, sent|optional },
10225     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10226     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10227     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10228     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10229     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10230     { WM_MOVE, sent|defwinproc|optional },
10231     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10232     { 0 }
10233 };
10234
10235 static void test_ShowWindow(void)
10236 {
10237     /* ShowWindow commands in random order */
10238     static const struct
10239     {
10240         INT cmd; /* ShowWindow command */
10241         LPARAM ret; /* ShowWindow return value */
10242         DWORD style; /* window style after the command */
10243         const struct message *msg; /* message sequence the command produces */
10244         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10245     } sw[] =
10246     {
10247 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10248 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10249 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10250 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10251 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10252 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10253 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10254 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10255 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10256 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10257 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10258 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10259 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10260 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10261 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10262 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10263 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10264 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10265 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10266 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10267 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10268 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10269 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10270 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10271 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10272 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10273 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10274 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10275 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10276 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10277 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10278 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10279 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10280 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10281 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10282 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10283 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10284 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10285 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10286 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10287 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10288 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE },
10289 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10290 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10291 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10292 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10293 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10294 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10295 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10296 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10297 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10298 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10299 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10300 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10301 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10302 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10303 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10304     };
10305     HWND hwnd;
10306     DWORD style;
10307     LPARAM ret;
10308     INT i;
10309
10310 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10311     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10312                           120, 120, 90, 90,
10313                           0, 0, 0, NULL);
10314     assert(hwnd);
10315
10316     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10317     ok(style == 0, "expected style 0, got %08x\n", style);
10318
10319     flush_events();
10320     flush_sequence();
10321
10322     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10323     {
10324         static const char * const sw_cmd_name[13] =
10325         {
10326             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10327             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10328             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10329             "SW_NORMALNA" /* 0xCC */
10330         };
10331         char comment[64];
10332         INT idx; /* index into the above array of names */
10333
10334         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10335
10336         style = GetWindowLong(hwnd, GWL_STYLE);
10337         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10338         ret = ShowWindow(hwnd, sw[i].cmd);
10339         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10340         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10341         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10342
10343         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10344         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10345
10346         flush_events();
10347         flush_sequence();
10348     }
10349
10350     DestroyWindow(hwnd);
10351 }
10352
10353 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10354 {
10355     struct recvd_message msg;
10356
10357     if (ignore_message( message )) return 0;
10358
10359     msg.hwnd = hwnd;
10360     msg.message = message;
10361     msg.flags = sent|wparam|lparam;
10362     msg.wParam = wParam;
10363     msg.lParam = lParam;
10364     msg.descr = "dialog";
10365     add_message(&msg);
10366
10367     /* calling DefDlgProc leads to a recursion under XP */
10368
10369     switch (message)
10370     {
10371     case WM_INITDIALOG:
10372     case WM_GETDLGCODE:
10373         return 0;
10374     }
10375     return 1;
10376 }
10377
10378 static const struct message WmDefDlgSetFocus_1[] = {
10379     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10380     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10381     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10382     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10383     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10384     { HCBT_SETFOCUS, hook },
10385     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10386     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10387     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10388     { WM_SETFOCUS, sent|wparam, 0 },
10389     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10390     { WM_CTLCOLOREDIT, sent },
10391     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10392     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10393     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10394     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10395     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10396     { 0 }
10397 };
10398 static const struct message WmDefDlgSetFocus_2[] = {
10399     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10400     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10401     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10402     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10403     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10404     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10405     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10406     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10407     { 0 }
10408 };
10409 /* Creation of a dialog */
10410 static const struct message WmCreateDialogParamSeq_1[] = {
10411     { HCBT_CREATEWND, hook },
10412     { WM_NCCREATE, sent },
10413     { WM_NCCALCSIZE, sent|wparam, 0 },
10414     { WM_CREATE, sent },
10415     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10416     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10417     { WM_MOVE, sent },
10418     { WM_SETFONT, sent },
10419     { WM_INITDIALOG, sent },
10420     { WM_CHANGEUISTATE, sent|optional },
10421     { 0 }
10422 };
10423 /* Creation of a dialog */
10424 static const struct message WmCreateDialogParamSeq_2[] = {
10425     { HCBT_CREATEWND, hook },
10426     { WM_NCCREATE, sent },
10427     { WM_NCCALCSIZE, sent|wparam, 0 },
10428     { WM_CREATE, sent },
10429     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10430     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10431     { WM_MOVE, sent },
10432     { WM_CHANGEUISTATE, sent|optional },
10433     { 0 }
10434 };
10435
10436 static void test_dialog_messages(void)
10437 {
10438     WNDCLASS cls;
10439     HWND hdlg, hedit1, hedit2, hfocus;
10440     LRESULT ret;
10441
10442 #define set_selection(hctl, start, end) \
10443     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10444     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10445
10446 #define check_selection(hctl, start, end) \
10447     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10448     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10449
10450     subclass_edit();
10451
10452     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10453                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10454                           0, 0, 100, 100, 0, 0, 0, NULL);
10455     ok(hdlg != 0, "Failed to create custom dialog window\n");
10456
10457     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10458                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10459                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10460     ok(hedit1 != 0, "Failed to create edit control\n");
10461     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10462                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10463                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10464     ok(hedit2 != 0, "Failed to create edit control\n");
10465
10466     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10467     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10468
10469     hfocus = GetFocus();
10470     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10471
10472     SetFocus(hedit2);
10473     hfocus = GetFocus();
10474     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10475
10476     check_selection(hedit1, 0, 0);
10477     check_selection(hedit2, 0, 0);
10478
10479     set_selection(hedit2, 0, -1);
10480     check_selection(hedit2, 0, 3);
10481
10482     SetFocus(0);
10483     hfocus = GetFocus();
10484     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10485
10486     flush_sequence();
10487     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10488     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10489     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10490
10491     hfocus = GetFocus();
10492     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10493
10494     check_selection(hedit1, 0, 5);
10495     check_selection(hedit2, 0, 3);
10496
10497     flush_sequence();
10498     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10499     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10500     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10501
10502     hfocus = GetFocus();
10503     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10504
10505     check_selection(hedit1, 0, 5);
10506     check_selection(hedit2, 0, 3);
10507
10508     EndDialog(hdlg, 0);
10509     DestroyWindow(hedit1);
10510     DestroyWindow(hedit2);
10511     DestroyWindow(hdlg);
10512     flush_sequence();
10513
10514 #undef set_selection
10515 #undef check_selection
10516
10517     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10518     cls.lpszClassName = "MyDialogClass";
10519     cls.hInstance = GetModuleHandle(0);
10520     /* need a cast since a dlgproc is used as a wndproc */
10521     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10522     if (!RegisterClass(&cls)) assert(0);
10523
10524     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10525     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10526     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10527     EndDialog(hdlg, 0);
10528     DestroyWindow(hdlg);
10529     flush_sequence();
10530
10531     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10532     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10533     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10534     EndDialog(hdlg, 0);
10535     DestroyWindow(hdlg);
10536     flush_sequence();
10537
10538     UnregisterClass(cls.lpszClassName, cls.hInstance);
10539 }
10540
10541 static void test_nullCallback(void)
10542 {
10543     HWND hwnd;
10544
10545     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10546                            100, 100, 200, 200, 0, 0, 0, NULL);
10547     ok (hwnd != 0, "Failed to create overlapped window\n");
10548
10549     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10550     flush_events();
10551     DestroyWindow(hwnd);
10552 }
10553
10554 /* SetActiveWindow( 0 ) hwnd visible */
10555 static const struct message SetActiveWindowSeq0[] =
10556 {
10557     { HCBT_ACTIVATE, hook|optional },
10558     { WM_NCACTIVATE, sent|wparam, 0 },
10559     { WM_GETTEXT, sent|defwinproc|optional },
10560     { WM_ACTIVATE, sent|wparam, 0 },
10561     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10562     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10563     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10564     { WM_KILLFOCUS, sent|optional },
10565     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10566     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10567     { WM_NCACTIVATE, sent|wparam|optional, 1 },
10568     { WM_GETTEXT, sent|defwinproc|optional },
10569     { WM_ACTIVATE, sent|wparam|optional, 1 },
10570     { HCBT_SETFOCUS, hook|optional },
10571     { WM_KILLFOCUS, sent|defwinproc|optional },
10572     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10573     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10574     { WM_IME_SETCONTEXT, sent|optional },
10575     { WM_IME_SETCONTEXT, sent|optional },
10576     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10577     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10578     { WM_SETFOCUS, sent|defwinproc|optional },
10579     { WM_GETTEXT, sent|optional },
10580     { 0 }
10581 };
10582 /* SetActiveWindow( hwnd ) hwnd visible */
10583 static const struct message SetActiveWindowSeq1[] =
10584 {
10585     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10586     { 0 }
10587 };
10588 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10589 static const struct message SetActiveWindowSeq2[] =
10590 {
10591     { HCBT_ACTIVATE, hook },
10592     { WM_NCACTIVATE, sent|wparam, 0 },
10593     { WM_GETTEXT, sent|defwinproc|optional },
10594     { WM_ACTIVATE, sent|wparam, 0 },
10595     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10596     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10597     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10598     { WM_NCPAINT, sent|optional },
10599     { WM_GETTEXT, sent|defwinproc|optional },
10600     { WM_ERASEBKGND, sent|optional },
10601     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10602     { WM_NCACTIVATE, sent|wparam, 1 },
10603     { WM_GETTEXT, sent|defwinproc|optional },
10604     { WM_ACTIVATE, sent|wparam, 1 },
10605     { HCBT_SETFOCUS, hook },
10606     { WM_KILLFOCUS, sent|defwinproc },
10607     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10608     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10609     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10610     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10611     { WM_SETFOCUS, sent|defwinproc },
10612     { WM_GETTEXT, sent|optional },
10613     { 0 }
10614 };
10615
10616 /* SetActiveWindow( hwnd ) hwnd not visible */
10617 static const struct message SetActiveWindowSeq3[] =
10618 {
10619     { HCBT_ACTIVATE, hook },
10620     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10621     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10622     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10623     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10624     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10625     { WM_ACTIVATEAPP, sent|wparam, 1 },
10626     { WM_ACTIVATEAPP, sent|wparam, 1 },
10627     { WM_NCACTIVATE, sent|wparam, 1 },
10628     { WM_ACTIVATE, sent|wparam, 1 },
10629     { HCBT_SETFOCUS, hook },
10630     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10631     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10632     { WM_SETFOCUS, sent|defwinproc },
10633     { 0 }
10634 };
10635 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10636 static const struct message SetActiveWindowSeq4[] =
10637 {
10638     { HCBT_ACTIVATE, hook },
10639     { WM_NCACTIVATE, sent|wparam, 0 },
10640     { WM_GETTEXT, sent|defwinproc|optional },
10641     { WM_ACTIVATE, sent|wparam, 0 },
10642     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10643     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10644     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10645     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10646     { WM_NCACTIVATE, sent|wparam, 1 },
10647     { WM_GETTEXT, sent|defwinproc|optional },
10648     { WM_ACTIVATE, sent|wparam, 1 },
10649     { HCBT_SETFOCUS, hook },
10650     { WM_KILLFOCUS, sent|defwinproc },
10651     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10652     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10653     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10654     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10655     { WM_SETFOCUS, sent|defwinproc },
10656     { 0 }
10657 };
10658
10659
10660 static void test_SetActiveWindow(void)
10661 {
10662     HWND hwnd, popup, ret;
10663
10664     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10665                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10666                            100, 100, 200, 200, 0, 0, 0, NULL);
10667
10668     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10669                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10670                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10671
10672     ok(hwnd != 0, "Failed to create overlapped window\n");
10673     ok(popup != 0, "Failed to create popup window\n");
10674     SetForegroundWindow( popup );
10675     flush_sequence();
10676
10677     trace("SetActiveWindow(0)\n");
10678     ret = SetActiveWindow(0);
10679     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10680     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
10681     flush_sequence();
10682
10683     trace("SetActiveWindow(hwnd), hwnd visible\n");
10684     ret = SetActiveWindow(hwnd);
10685     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10686     flush_sequence();
10687
10688     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10689     ret = SetActiveWindow(popup);
10690     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10691     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10692     flush_sequence();
10693
10694     ShowWindow(hwnd, SW_HIDE);
10695     ShowWindow(popup, SW_HIDE);
10696     flush_sequence();
10697
10698     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10699     ret = SetActiveWindow(hwnd);
10700     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
10701     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10702     flush_sequence();
10703
10704     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10705     ret = SetActiveWindow(popup);
10706     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10707     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10708     flush_sequence();
10709
10710     trace("done\n");
10711
10712     DestroyWindow(hwnd);
10713 }
10714
10715 static const struct message SetForegroundWindowSeq[] =
10716 {
10717     { WM_NCACTIVATE, sent|wparam, 0 },
10718     { WM_GETTEXT, sent|defwinproc|optional },
10719     { WM_ACTIVATE, sent|wparam, 0 },
10720     { WM_ACTIVATEAPP, sent|wparam, 0 },
10721     { WM_KILLFOCUS, sent },
10722     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10723     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10724     { 0 }
10725 };
10726
10727 static void test_SetForegroundWindow(void)
10728 {
10729     HWND hwnd;
10730
10731     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10732                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10733                            100, 100, 200, 200, 0, 0, 0, NULL);
10734     ok (hwnd != 0, "Failed to create overlapped window\n");
10735     SetForegroundWindow( hwnd );
10736     flush_sequence();
10737
10738     trace("SetForegroundWindow( 0 )\n");
10739     SetForegroundWindow( 0 );
10740     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10741     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10742     SetForegroundWindow( GetDesktopWindow() );
10743     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10744                                         "foreground top level window", FALSE);
10745     trace("done\n");
10746
10747     DestroyWindow(hwnd);
10748 }
10749
10750 static void test_dbcs_wm_char(void)
10751 {
10752     BYTE dbch[2];
10753     WCHAR wch, bad_wch;
10754     HWND hwnd, hwnd2;
10755     MSG msg;
10756     DWORD time;
10757     POINT pt;
10758     DWORD_PTR res;
10759     CPINFOEXA cpinfo;
10760     UINT i, j, k;
10761     struct message wmCharSeq[2];
10762
10763     if (!pGetCPInfoExA)
10764     {
10765         win_skip("GetCPInfoExA is not available\n");
10766         return;
10767     }
10768
10769     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10770     if (cpinfo.MaxCharSize != 2)
10771     {
10772         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10773         return;
10774     }
10775
10776     dbch[0] = dbch[1] = 0;
10777     wch = 0;
10778     bad_wch = cpinfo.UnicodeDefaultChar;
10779     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10780         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10781             for (k = 128; k <= 255; k++)
10782             {
10783                 char str[2];
10784                 WCHAR wstr[2];
10785                 str[0] = j;
10786                 str[1] = k;
10787                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10788                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10789                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10790                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10791                 {
10792                     dbch[0] = j;
10793                     dbch[1] = k;
10794                     wch = wstr[0];
10795                     break;
10796                 }
10797             }
10798
10799     if (!wch)
10800     {
10801         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10802         return;
10803     }
10804     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10805            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10806
10807     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10808                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10809     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10810                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10811     ok (hwnd != 0, "Failed to create overlapped window\n");
10812     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10813     flush_sequence();
10814
10815     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10816     wmCharSeq[0].message = WM_CHAR;
10817     wmCharSeq[0].flags = sent|wparam;
10818     wmCharSeq[0].wParam = wch;
10819
10820     /* posted message */
10821     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10822     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10823     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10824     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10825     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10826     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10827     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10828
10829     /* posted thread message */
10830     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10831     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10832     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10833     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10834     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10835     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10836     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10837
10838     /* sent message */
10839     flush_sequence();
10840     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10841     ok_sequence( WmEmptySeq, "no messages", FALSE );
10842     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10843     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10844     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10845
10846     /* sent message with timeout */
10847     flush_sequence();
10848     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10849     ok_sequence( WmEmptySeq, "no messages", FALSE );
10850     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10851     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10852     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10853
10854     /* sent message with timeout and callback */
10855     flush_sequence();
10856     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10857     ok_sequence( WmEmptySeq, "no messages", FALSE );
10858     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10859     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10860     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10861
10862     /* sent message with callback */
10863     flush_sequence();
10864     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10865     ok_sequence( WmEmptySeq, "no messages", FALSE );
10866     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10867     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10868     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10869
10870     /* direct window proc call */
10871     flush_sequence();
10872     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10873     ok_sequence( WmEmptySeq, "no messages", FALSE );
10874     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10875     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10876
10877     /* dispatch message */
10878     msg.hwnd = hwnd;
10879     msg.message = WM_CHAR;
10880     msg.wParam = dbch[0];
10881     msg.lParam = 0;
10882     DispatchMessageA( &msg );
10883     ok_sequence( WmEmptySeq, "no messages", FALSE );
10884     msg.wParam = dbch[1];
10885     DispatchMessageA( &msg );
10886     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10887
10888     /* window handle is irrelevant */
10889     flush_sequence();
10890     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10891     ok_sequence( WmEmptySeq, "no messages", FALSE );
10892     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10893     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10894     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10895
10896     /* interleaved post and send */
10897     flush_sequence();
10898     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10899     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10900     ok_sequence( WmEmptySeq, "no messages", FALSE );
10901     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10902     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10903     ok_sequence( WmEmptySeq, "no messages", FALSE );
10904     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10905     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10906     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10907     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10908     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10909     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10910     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10911
10912     /* interleaved sent message and winproc */
10913     flush_sequence();
10914     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10915     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10916     ok_sequence( WmEmptySeq, "no messages", FALSE );
10917     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10918     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10919     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10920     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10921
10922     /* interleaved winproc and dispatch */
10923     msg.hwnd = hwnd;
10924     msg.message = WM_CHAR;
10925     msg.wParam = dbch[0];
10926     msg.lParam = 0;
10927     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10928     DispatchMessageA( &msg );
10929     ok_sequence( WmEmptySeq, "no messages", FALSE );
10930     msg.wParam = dbch[1];
10931     DispatchMessageA( &msg );
10932     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10933     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10934     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10935
10936     /* interleaved sends */
10937     flush_sequence();
10938     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10939     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10940     ok_sequence( WmEmptySeq, "no messages", FALSE );
10941     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10942     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10943     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10944     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10945
10946     /* dbcs WM_CHAR */
10947     flush_sequence();
10948     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10949     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10950     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10951
10952     /* other char messages are not magic */
10953     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10954     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10955     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10956     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10957     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10958     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10959     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10960     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10961     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10962     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10963
10964     /* test retrieving messages */
10965
10966     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10967     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10968     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10969     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10970     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10971     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10972     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10973     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10974     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10975     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10976
10977     /* message filters */
10978     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10979     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10980     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10981     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10982     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10983     /* message id is filtered, hwnd is not */
10984     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10985     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10986     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10987     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10988     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10989     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10990
10991     /* mixing GetMessage and PostMessage */
10992     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10993     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10994     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10995     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10996     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10997     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10998     time = msg.time;
10999     pt = msg.pt;
11000     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11001     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11002     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11003     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11004     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11005     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11006     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11007     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 );
11008     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11009
11010     /* without PM_REMOVE */
11011     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11012     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11013     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11014     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11015     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11016     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11017     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11018     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11019     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11020     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11021     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11022     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11023     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11024     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11025     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11026     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11027     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11028     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11029
11030     DestroyWindow(hwnd);
11031 }
11032
11033 #define ID_LISTBOX 0x000f
11034
11035 static const struct message wm_lb_setcursel_0[] =
11036 {
11037     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11038     { WM_CTLCOLORLISTBOX, sent|parent },
11039     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11040     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11041     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11042     { 0 }
11043 };
11044 static const struct message wm_lb_setcursel_1[] =
11045 {
11046     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11047     { WM_CTLCOLORLISTBOX, sent|parent },
11048     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11049     { WM_CTLCOLORLISTBOX, sent|parent },
11050     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11051     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11052     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11053     { 0 }
11054 };
11055 static const struct message wm_lb_setcursel_2[] =
11056 {
11057     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11058     { WM_CTLCOLORLISTBOX, sent|parent },
11059     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11060     { WM_CTLCOLORLISTBOX, sent|parent },
11061     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11062     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11063     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11064     { 0 }
11065 };
11066 static const struct message wm_lb_click_0[] =
11067 {
11068     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11069     { HCBT_SETFOCUS, hook },
11070     { WM_KILLFOCUS, sent|parent },
11071     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11072     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11073     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11074     { WM_SETFOCUS, sent|defwinproc },
11075
11076     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11077     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11078     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11079     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11080     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11081
11082     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11083     { WM_CTLCOLORLISTBOX, sent|parent },
11084     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11085     { WM_CTLCOLORLISTBOX, sent|parent },
11086     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11087     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11088
11089     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11090     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11091
11092     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11093     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11094     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11095     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11096     { 0 }
11097 };
11098 static const struct message wm_lb_deletestring[] =
11099 {
11100     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11101     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11102     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11103     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11104     { 0 }
11105 };
11106 static const struct message wm_lb_deletestring_reset[] =
11107 {
11108     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11109     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11110     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11111     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11112     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11113     { 0 }
11114 };
11115
11116 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11117
11118 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11119
11120 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11121 {
11122     static LONG defwndproc_counter = 0;
11123     LRESULT ret;
11124     struct recvd_message msg;
11125
11126     /* do not log painting messages */
11127     if (message != WM_PAINT &&
11128         message != WM_NCPAINT &&
11129         message != WM_SYNCPAINT &&
11130         message != WM_ERASEBKGND &&
11131         message != WM_NCHITTEST &&
11132         message != WM_GETTEXT &&
11133         !ignore_message( message ))
11134     {
11135         msg.hwnd = hwnd;
11136         msg.message = message;
11137         msg.flags = sent|wparam|lparam;
11138         if (defwndproc_counter) msg.flags |= defwinproc;
11139         msg.wParam = wp;
11140         msg.lParam = lp;
11141         msg.descr = "listbox";
11142         add_message(&msg);
11143     }
11144
11145     defwndproc_counter++;
11146     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11147     defwndproc_counter--;
11148
11149     return ret;
11150 }
11151
11152 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11153                                int caret_index, int top_index, int line)
11154 {
11155     LRESULT ret;
11156
11157     /* calling an orig proc helps to avoid unnecessary message logging */
11158     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11159     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11160     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11161     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11162     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11163     ok_(__FILE__, line)(ret == caret_index ||
11164                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11165                         "expected caret index %d, got %ld\n", caret_index, ret);
11166     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11167     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11168 }
11169
11170 static void test_listbox_messages(void)
11171 {
11172     HWND parent, listbox;
11173     LRESULT ret;
11174
11175     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11176                              100, 100, 200, 200, 0, 0, 0, NULL);
11177     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11178                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11179                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11180     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11181
11182     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11183
11184     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11185     ok(ret == 0, "expected 0, got %ld\n", ret);
11186     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11187     ok(ret == 1, "expected 1, got %ld\n", ret);
11188     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11189     ok(ret == 2, "expected 2, got %ld\n", ret);
11190
11191     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11192
11193     flush_sequence();
11194
11195     log_all_parent_messages++;
11196
11197     trace("selecting item 0\n");
11198     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11199     ok(ret == 0, "expected 0, got %ld\n", ret);
11200     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11201     check_lb_state(listbox, 3, 0, 0, 0);
11202     flush_sequence();
11203
11204     trace("selecting item 1\n");
11205     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11206     ok(ret == 1, "expected 1, got %ld\n", ret);
11207     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11208     check_lb_state(listbox, 3, 1, 1, 0);
11209
11210     trace("selecting item 2\n");
11211     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11212     ok(ret == 2, "expected 2, got %ld\n", ret);
11213     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11214     check_lb_state(listbox, 3, 2, 2, 0);
11215
11216     trace("clicking on item 0\n");
11217     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11218     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11219     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11220     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11221     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11222     check_lb_state(listbox, 3, 0, 0, 0);
11223     flush_sequence();
11224
11225     trace("deleting item 0\n");
11226     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11227     ok(ret == 2, "expected 2, got %ld\n", ret);
11228     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11229     check_lb_state(listbox, 2, -1, 0, 0);
11230     flush_sequence();
11231
11232     trace("deleting item 0\n");
11233     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11234     ok(ret == 1, "expected 1, got %ld\n", ret);
11235     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11236     check_lb_state(listbox, 1, -1, 0, 0);
11237     flush_sequence();
11238
11239     trace("deleting item 0\n");
11240     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11241     ok(ret == 0, "expected 0, got %ld\n", ret);
11242     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11243     check_lb_state(listbox, 0, -1, 0, 0);
11244     flush_sequence();
11245
11246     trace("deleting item 0\n");
11247     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11248     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11249     check_lb_state(listbox, 0, -1, 0, 0);
11250     flush_sequence();
11251
11252     log_all_parent_messages--;
11253
11254     DestroyWindow(listbox);
11255     DestroyWindow(parent);
11256 }
11257
11258 /*************************** Menu test ******************************/
11259 static const struct message wm_popup_menu_1[] =
11260 {
11261     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11262     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11263     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11264     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11265     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11266     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11267     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11268     { WM_INITMENU, sent|lparam, 0, 0 },
11269     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11270     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11271     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11272     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11273     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11274     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11275     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11276     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11277     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11278     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11279     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11280     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11281     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11282     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11283     { 0 }
11284 };
11285 static const struct message wm_popup_menu_2[] =
11286 {
11287     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11288     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11289     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11290     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11291     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11292     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11293     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11294     { WM_INITMENU, sent|lparam, 0, 0 },
11295     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11296     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11297     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11298     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11299     { HCBT_CREATEWND, hook },
11300     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11301                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11302     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11303     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11304     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11305     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11306     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11307     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11308     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11309     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11310     { HCBT_DESTROYWND, hook },
11311     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11312     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11313     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11314     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11315     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11316     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11317     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11318     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11319     { 0 }
11320 };
11321 static const struct message wm_popup_menu_3[] =
11322 {
11323     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11324     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11325     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11326     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11327     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11328     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11329     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11330     { WM_INITMENU, sent|lparam, 0, 0 },
11331     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11332     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11333     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11334     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11335     { HCBT_CREATEWND, hook },
11336     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11337                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11338     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11339     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11340     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11341     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11342     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11343     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11344     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11345     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11346     { HCBT_DESTROYWND, hook },
11347     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11348     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11349     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11350     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11351     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11352     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11353     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11354     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11355     { 0 }
11356 };
11357
11358 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11359 {
11360     if (message == WM_ENTERIDLE ||
11361         message == WM_INITMENU ||
11362         message == WM_INITMENUPOPUP ||
11363         message == WM_MENUSELECT ||
11364         message == WM_PARENTNOTIFY ||
11365         message == WM_ENTERMENULOOP ||
11366         message == WM_EXITMENULOOP ||
11367         message == WM_UNINITMENUPOPUP ||
11368         message == WM_KEYDOWN ||
11369         message == WM_KEYUP ||
11370         message == WM_CHAR ||
11371         message == WM_SYSKEYDOWN ||
11372         message == WM_SYSKEYUP ||
11373         message == WM_SYSCHAR ||
11374         message == WM_COMMAND ||
11375         message == WM_MENUCOMMAND)
11376     {
11377         struct recvd_message msg;
11378
11379         msg.hwnd = hwnd;
11380         msg.message = message;
11381         msg.flags = sent|wparam|lparam;
11382         msg.wParam = wp;
11383         msg.lParam = lp;
11384         msg.descr = "parent_menu_proc";
11385         add_message(&msg);
11386     }
11387
11388     return DefWindowProcA(hwnd, message, wp, lp);
11389 }
11390
11391 static void set_menu_style(HMENU hmenu, DWORD style)
11392 {
11393     MENUINFO mi;
11394     BOOL ret;
11395
11396     mi.cbSize = sizeof(mi);
11397     mi.fMask = MIM_STYLE;
11398     mi.dwStyle = style;
11399     SetLastError(0xdeadbeef);
11400     ret = pSetMenuInfo(hmenu, &mi);
11401     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11402 }
11403
11404 static DWORD get_menu_style(HMENU hmenu)
11405 {
11406     MENUINFO mi;
11407     BOOL ret;
11408
11409     mi.cbSize = sizeof(mi);
11410     mi.fMask = MIM_STYLE;
11411     mi.dwStyle = 0;
11412     SetLastError(0xdeadbeef);
11413     ret = pGetMenuInfo(hmenu, &mi);
11414     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11415
11416     return mi.dwStyle;
11417 }
11418
11419 static void test_menu_messages(void)
11420 {
11421     MSG msg;
11422     WNDCLASSA cls;
11423     HMENU hmenu, hmenu_popup;
11424     HWND hwnd;
11425     DWORD style;
11426
11427     if (!pGetMenuInfo || !pSetMenuInfo)
11428     {
11429         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11430         return;
11431     }
11432     cls.style = 0;
11433     cls.lpfnWndProc = parent_menu_proc;
11434     cls.cbClsExtra = 0;
11435     cls.cbWndExtra = 0;
11436     cls.hInstance = GetModuleHandleA(0);
11437     cls.hIcon = 0;
11438     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11439     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11440     cls.lpszMenuName = NULL;
11441     cls.lpszClassName = "TestMenuClass";
11442     UnregisterClass(cls.lpszClassName, cls.hInstance);
11443     if (!RegisterClassA(&cls)) assert(0);
11444
11445     SetLastError(0xdeadbeef);
11446     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11447                            100, 100, 200, 200, 0, 0, 0, NULL);
11448     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11449
11450     SetLastError(0xdeadbeef);
11451     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11452     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11453
11454     SetMenu(hwnd, hmenu);
11455     SetForegroundWindow( hwnd );
11456
11457     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11458     style = get_menu_style(hmenu);
11459     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11460
11461     hmenu_popup = GetSubMenu(hmenu, 0);
11462     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11463     style = get_menu_style(hmenu_popup);
11464     ok(style == 0, "expected 0, got %u\n", style);
11465
11466     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11467     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11468     style = get_menu_style(hmenu_popup);
11469     ok(style == 0, "expected 0, got %u\n", style);
11470
11471     /* Alt+E, Enter */
11472     trace("testing a popup menu command\n");
11473     flush_sequence();
11474     keybd_event(VK_MENU, 0, 0, 0);
11475     keybd_event('E', 0, 0, 0);
11476     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11477     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11478     keybd_event(VK_RETURN, 0, 0, 0);
11479     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11480     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11481     {
11482         TranslateMessage(&msg);
11483         DispatchMessage(&msg);
11484     }
11485     if (!sequence_cnt)  /* we didn't get any message */
11486     {
11487         skip( "queuing key events not supported\n" );
11488         goto done;
11489     }
11490     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
11491     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
11492     {
11493         win_skip( "menu tracking through VK_MENU not supported\n" );
11494         goto done;
11495     }
11496     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11497
11498     /* Alt+F, Right, Enter */
11499     trace("testing submenu of a popup menu command\n");
11500     flush_sequence();
11501     keybd_event(VK_MENU, 0, 0, 0);
11502     keybd_event('F', 0, 0, 0);
11503     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11504     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11505     keybd_event(VK_RIGHT, 0, 0, 0);
11506     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11507     keybd_event(VK_RETURN, 0, 0, 0);
11508     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11509     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11510     {
11511         TranslateMessage(&msg);
11512         DispatchMessage(&msg);
11513     }
11514     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11515
11516     set_menu_style(hmenu, 0);
11517     style = get_menu_style(hmenu);
11518     ok(style == 0, "expected 0, got %u\n", style);
11519
11520     hmenu_popup = GetSubMenu(hmenu, 0);
11521     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11522     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11523     style = get_menu_style(hmenu_popup);
11524     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11525
11526     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11527     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11528     style = get_menu_style(hmenu_popup);
11529     ok(style == 0, "expected 0, got %u\n", style);
11530
11531     /* Alt+F, Right, Enter */
11532     trace("testing submenu of a popup menu command\n");
11533     flush_sequence();
11534     keybd_event(VK_MENU, 0, 0, 0);
11535     keybd_event('F', 0, 0, 0);
11536     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11537     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11538     keybd_event(VK_RIGHT, 0, 0, 0);
11539     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11540     keybd_event(VK_RETURN, 0, 0, 0);
11541     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11542     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11543     {
11544         TranslateMessage(&msg);
11545         DispatchMessage(&msg);
11546     }
11547     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11548
11549 done:
11550     DestroyWindow(hwnd);
11551     DestroyMenu(hmenu);
11552 }
11553
11554
11555 static void test_paintingloop(void)
11556 {
11557     HWND hwnd;
11558
11559     paint_loop_done = 0;
11560     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11561                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11562                                 100, 100, 100, 100, 0, 0, 0, NULL );
11563     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11564     ShowWindow(hwnd,SW_NORMAL);
11565     SetFocus(hwnd);
11566
11567     while (!paint_loop_done)
11568     {
11569         MSG msg;
11570         if (PeekMessageA(&msg, 0, 0, 0, 1))
11571         {
11572             TranslateMessage(&msg);
11573             DispatchMessage(&msg);
11574         }
11575     }
11576     DestroyWindow(hwnd);
11577 }
11578
11579 static void test_defwinproc(void)
11580 {
11581     HWND hwnd;
11582     MSG msg;
11583     int gotwmquit = FALSE;
11584     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
11585     assert(hwnd);
11586     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
11587     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
11588         if( msg.message == WM_QUIT) gotwmquit = TRUE;
11589         DispatchMessageA( &msg );
11590     }
11591     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
11592     DestroyWindow( hwnd);
11593 }
11594
11595 START_TEST(msg)
11596 {
11597     BOOL ret;
11598     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11599
11600     init_procs();
11601
11602     if (!RegisterWindowClasses()) assert(0);
11603
11604     if (pSetWinEventHook)
11605     {
11606         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11607                                        GetModuleHandleA(0), win_event_proc,
11608                                        0, GetCurrentThreadId(),
11609                                        WINEVENT_INCONTEXT);
11610         if (pIsWinEventHookInstalled && hEvent_hook)
11611         {
11612             UINT event;
11613             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11614                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11615         }
11616     }
11617     if (!hEvent_hook) win_skip( "no win event hook support\n" );
11618
11619     cbt_hook_thread_id = GetCurrentThreadId();
11620     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11621     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
11622
11623     test_winevents();
11624
11625     /* Fix message sequences before removing 4 lines below */
11626 #if 1
11627     if (pUnhookWinEvent && hEvent_hook)
11628     {
11629         ret = pUnhookWinEvent(hEvent_hook);
11630         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11631         pUnhookWinEvent = 0;
11632     }
11633     hEvent_hook = 0;
11634 #endif
11635
11636     test_ShowWindow();
11637     test_PeekMessage();
11638     test_PeekMessage2();
11639     test_scrollwindowex();
11640     test_messages();
11641     test_setwindowpos();
11642     test_showwindow();
11643     invisible_parent_tests();
11644     test_mdi_messages();
11645     test_button_messages();
11646     test_static_messages();
11647     test_listbox_messages();
11648     test_combobox_messages();
11649     test_wmime_keydown_message();
11650     test_paint_messages();
11651     test_interthread_messages();
11652     test_message_conversion();
11653     test_accelerators();
11654     test_timers();
11655     test_timers_no_wnd();
11656     if (hCBT_hook) test_set_hook();
11657     test_DestroyWindow();
11658     test_DispatchMessage();
11659     test_SendMessageTimeout();
11660     test_edit_messages();
11661     test_quit_message();
11662     test_SetActiveWindow();
11663
11664     if (!pTrackMouseEvent)
11665         win_skip("TrackMouseEvent is not available\n");
11666     else
11667         test_TrackMouseEvent();
11668
11669     test_SetWindowRgn();
11670     test_sys_menu();
11671     test_dialog_messages();
11672     test_nullCallback();
11673     test_dbcs_wm_char();
11674     test_menu_messages();
11675     test_paintingloop();
11676     test_defwinproc();
11677     /* keep it the last test, under Windows it tends to break the tests
11678      * which rely on active/foreground windows being correct.
11679      */
11680     test_SetForegroundWindow();
11681
11682     UnhookWindowsHookEx(hCBT_hook);
11683     if (pUnhookWinEvent && hEvent_hook)
11684     {
11685         ret = pUnhookWinEvent(hEvent_hook);
11686         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11687         SetLastError(0xdeadbeef);
11688         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11689         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11690            GetLastError() == 0xdeadbeef, /* Win9x */
11691            "unexpected error %d\n", GetLastError());
11692     }
11693 }