Revert "winex11.drv: Optimise getting the bits of a DIB after calling SetDIBits."
[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 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
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
82 static void dump_winpos_flags(UINT flags);
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 };
116
117 /* Empty message sequence */
118 static const struct message WmEmptySeq[] =
119 {
120     { 0 }
121 };
122 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
123 static const struct message WmCreateOverlappedSeq[] = {
124     { HCBT_CREATEWND, hook },
125     { WM_GETMINMAXINFO, sent },
126     { WM_NCCREATE, sent },
127     { WM_NCCALCSIZE, sent|wparam, 0 },
128     { 0x0093, sent|defwinproc|optional },
129     { 0x0094, sent|defwinproc|optional },
130     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
131     { WM_CREATE, sent },
132     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
133     { 0 }
134 };
135 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
136  * for a not visible overlapped window.
137  */
138 static const struct message WmSWP_ShowOverlappedSeq[] = {
139     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
140     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
141     { WM_NCPAINT, sent|wparam|optional, 1 },
142     { WM_GETTEXT, sent|defwinproc|optional },
143     { WM_ERASEBKGND, sent|optional },
144     { HCBT_ACTIVATE, hook },
145     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
146     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
147     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
148     { WM_ACTIVATEAPP, sent|wparam, 1 },
149     { WM_NCACTIVATE, sent|wparam, 1 },
150     { WM_GETTEXT, sent|defwinproc|optional },
151     { WM_ACTIVATE, sent|wparam, 1 },
152     { HCBT_SETFOCUS, hook },
153     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
154     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
155     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
156     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
157     { WM_NCPAINT, sent|wparam|optional, 1 },
158     { WM_GETTEXT, sent|defwinproc|optional },
159     { WM_ERASEBKGND, sent|optional },
160     /* Win9x adds SWP_NOZORDER below */
161     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
162     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
163     { WM_NCPAINT, sent|wparam|optional, 1 },
164     { WM_ERASEBKGND, sent|optional },
165     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
166     { 0 }
167 };
168 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
169  * for a visible overlapped window.
170  */
171 static const struct message WmSWP_HideOverlappedSeq[] = {
172     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
173     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
174     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
175     { 0 }
176 };
177
178 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
179  * for a visible overlapped window.
180  */
181 static const struct message WmSWP_ResizeSeq[] = {
182     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
183     { WM_GETMINMAXINFO, sent|defwinproc },
184     { WM_NCCALCSIZE, sent|wparam, TRUE },
185     { WM_NCPAINT, sent|optional },
186     { WM_GETTEXT, sent|defwinproc|optional },
187     { WM_ERASEBKGND, sent|optional },
188     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
189     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
190     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
191     { WM_NCPAINT, sent|optional },
192     { WM_GETTEXT, sent|defwinproc|optional },
193     { WM_ERASEBKGND, sent|optional },
194     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
195     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
196     { 0 }
197 };
198
199 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
200  * for a visible popup window.
201  */
202 static const struct message WmSWP_ResizePopupSeq[] = {
203     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
204     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
205     { WM_NCCALCSIZE, sent|wparam, TRUE },
206     { WM_NCPAINT, sent|optional },
207     { WM_GETTEXT, sent|defwinproc|optional },
208     { WM_ERASEBKGND, sent|optional },
209     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
210     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
211     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
212     { WM_NCPAINT, sent|optional },
213     { WM_GETTEXT, sent|defwinproc|optional },
214     { WM_ERASEBKGND, sent|optional },
215     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
216     { 0 }
217 };
218
219 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
220  * for a visible overlapped window.
221  */
222 static const struct message WmSWP_MoveSeq[] = {
223     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
224     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
225     { WM_MOVE, sent|defwinproc|wparam, 0 },
226     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
227     { 0 }
228 };
229 /* Resize with SetWindowPos(SWP_NOZORDER)
230  * for a visible overlapped window
231  * SWP_NOZORDER is stripped by the logging code
232  */
233 static const struct message WmSWP_ResizeNoZOrder[] = {
234     { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
235     { WM_GETMINMAXINFO, sent|defwinproc },
236     { WM_NCCALCSIZE, sent|wparam, 1 },
237     { WM_NCPAINT, sent },
238     { WM_GETTEXT, sent|defwinproc|optional },
239     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
240     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
241     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
242     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
243     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
244     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
245     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
246     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
247     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
248     { 0 }
249 };
250
251 /* Switch visible mdi children */
252 static const struct message WmSwitchChild[] = {
253     /* Switch MDI child */
254     { WM_MDIACTIVATE, sent },/* in the MDI client */
255     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
256     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
257     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
258     /* Deactivate 2nd MDI child */
259     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
260     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
261     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
262     /* Preparing for maximize and maximaze the 1st MDI child */
263     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
264     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
265     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
266     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
267     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
268     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
269     /* Lock redraw 2nd MDI child */
270     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
271     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
272     /* Restore 2nd MDI child */
273     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
274     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
275     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
276     { 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 */
277     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
278     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
279     /* Redraw 2nd MDI child */
280     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
281     /* Redraw MDI frame */
282     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
283     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
284     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
285     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
286     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
287     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
288     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
289     { HCBT_SETFOCUS, hook },
290     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
291     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
292     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
293     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
294     { WM_SETFOCUS, sent },/* in the MDI client */
295     { HCBT_SETFOCUS, hook },
296     { WM_KILLFOCUS, sent },/* in the MDI client */
297     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
298     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
299     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
300     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
301     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
302     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
303     { 0 }
304 };
305
306 /* Switch visible not maximized mdi children */
307 static const struct message WmSwitchNotMaximizedChild[] = {
308     /* Switch not maximized MDI child */
309     { WM_MDIACTIVATE, sent },/* in the MDI client */
310     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
311     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
312     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
313     /* Deactivate 1st MDI child */
314     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
315     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
316     /* Activate 2nd MDI child */
317     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
318     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
319     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
320     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
321     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
322     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
323     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
324     { HCBT_SETFOCUS, hook },
325     { WM_KILLFOCUS, sent }, /* in the  MDI client */
326     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
327     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
328     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
329     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
330     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
331     { 0 }
332 };
333
334
335 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
336                 SWP_NOZORDER|SWP_FRAMECHANGED)
337  * for a visible overlapped window with WS_CLIPCHILDREN style set.
338  */
339 static const struct message WmSWP_FrameChanged_clip[] = {
340     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
341     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
342     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
343     { WM_GETTEXT, sent|parent|defwinproc|optional },
344     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
345     { WM_NCPAINT, sent }, /* wparam != 1 */
346     { WM_ERASEBKGND, sent },
347     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
348     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
349     { WM_PAINT, sent },
350     { 0 }
351 };
352 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
353                 SWP_NOZORDER|SWP_FRAMECHANGED)
354  * for a visible overlapped window.
355  */
356 static const struct message WmSWP_FrameChangedDeferErase[] = {
357     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
358     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
359     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
360     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
361     { WM_PAINT, sent|parent },
362     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
363     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
364     { WM_PAINT, sent },
365     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
366     { WM_ERASEBKGND, sent|beginpaint },
367     { 0 }
368 };
369
370 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
371                 SWP_NOZORDER|SWP_FRAMECHANGED)
372  * for a visible overlapped window without WS_CLIPCHILDREN style set.
373  */
374 static const struct message WmSWP_FrameChanged_noclip[] = {
375     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
376     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
377     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
378     { WM_GETTEXT, sent|parent|defwinproc|optional },
379     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
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     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
384     { WM_ERASEBKGND, sent|beginpaint },
385     { 0 }
386 };
387
388 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
389 static const struct message WmShowOverlappedSeq[] = {
390     { WM_SHOWWINDOW, sent|wparam, 1 },
391     { WM_NCPAINT, sent|wparam|optional, 1 },
392     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
393     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
394     { WM_NCPAINT, sent|wparam|optional, 1 },
395     { WM_GETTEXT, sent|defwinproc|optional },
396     { WM_ERASEBKGND, sent|optional },
397     { HCBT_ACTIVATE, hook },
398     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
399     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
400     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
401     { WM_NCPAINT, sent|wparam|optional, 1 },
402     { WM_ACTIVATEAPP, sent|wparam, 1 },
403     { WM_NCACTIVATE, sent|wparam, 1 },
404     { WM_GETTEXT, sent|defwinproc|optional },
405     { WM_ACTIVATE, sent|wparam, 1 },
406     { HCBT_SETFOCUS, hook },
407     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
408     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
409     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
410     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
411     { WM_NCPAINT, sent|wparam|optional, 1 },
412     { WM_GETTEXT, sent|defwinproc|optional },
413     { WM_ERASEBKGND, sent|optional },
414     /* Win9x adds SWP_NOZORDER below */
415     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
416     { WM_NCCALCSIZE, sent|optional },
417     { WM_NCPAINT, sent|optional },
418     { WM_ERASEBKGND, sent|optional },
419 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
420        * messages. Does that mean that CreateWindow doesn't set initial
421        * window dimensions for overlapped windows?
422        */
423     { WM_SIZE, sent },
424     { WM_MOVE, sent },
425 #endif
426     { 0 }
427 };
428 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
429 static const struct message WmShowMaxOverlappedSeq[] = {
430     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
431     { WM_GETMINMAXINFO, sent },
432     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
433     { WM_GETMINMAXINFO, sent|defwinproc },
434     { WM_NCCALCSIZE, sent|wparam, TRUE },
435     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
436     { HCBT_ACTIVATE, hook },
437     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
438     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
439     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
440     { WM_ACTIVATEAPP, sent|wparam, 1 },
441     { WM_NCACTIVATE, sent|wparam, 1 },
442     { WM_GETTEXT, sent|defwinproc|optional },
443     { WM_ACTIVATE, sent|wparam, 1 },
444     { HCBT_SETFOCUS, hook },
445     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
446     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
447     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
448     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
449     { WM_NCPAINT, sent|wparam|optional, 1 },
450     { WM_GETTEXT, sent|defwinproc|optional },
451     { WM_ERASEBKGND, sent|optional },
452     /* Win9x adds SWP_NOZORDER below */
453     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
454     { WM_MOVE, sent|defwinproc },
455     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
456     { WM_NCCALCSIZE, sent|optional },
457     { WM_NCPAINT, sent|optional },
458     { WM_ERASEBKGND, sent|optional },
459     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
460     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
461     { 0 }
462 };
463 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
464 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
465     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
466     { WM_GETTEXT, sent|optional },
467     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
468     { WM_GETMINMAXINFO, sent|defwinproc },
469     { WM_NCCALCSIZE, sent|wparam, TRUE },
470     { WM_NCPAINT, sent|wparam|optional, 1 },
471     { WM_GETTEXT, sent|defwinproc|optional },
472     { WM_ERASEBKGND, sent },
473     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
474     { WM_MOVE, sent|defwinproc },
475     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
476     { 0 }
477 };
478 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
479 static const struct message WmShowRestoreMinOverlappedSeq[] = {
480     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
481     { WM_QUERYOPEN, sent|optional },
482     { WM_GETTEXT, sent|optional },
483     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
484     { WM_GETMINMAXINFO, sent|defwinproc },
485     { WM_NCCALCSIZE, sent|wparam, TRUE },
486     { HCBT_ACTIVATE, hook },
487     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
488     { WM_ACTIVATEAPP, sent|wparam, 1 },
489     { WM_NCACTIVATE, sent|wparam, 1 },
490     { WM_GETTEXT, sent|defwinproc|optional },
491     { WM_ACTIVATE, sent|wparam, 1 },
492     { HCBT_SETFOCUS, hook },
493     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
494     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
495     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
496     { WM_NCPAINT, sent|wparam|optional, 1 },
497     { WM_GETTEXT, sent|defwinproc|optional },
498     { WM_ERASEBKGND, sent },
499     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
500     { WM_MOVE, sent|defwinproc },
501     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
502     { WM_ACTIVATE, sent|wparam, 1 },
503     { 0 }
504 };
505 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
506 static const struct message WmShowMinOverlappedSeq[] = {
507     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
508     { HCBT_SETFOCUS, hook },
509     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
510     { WM_KILLFOCUS, sent },
511     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
512     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
513     { WM_GETTEXT, sent|optional },
514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
515     { WM_GETMINMAXINFO, sent|defwinproc },
516     { WM_NCCALCSIZE, sent|wparam, TRUE },
517     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
518     { WM_NCPAINT, sent },
519     { WM_GETTEXT, sent|defwinproc|optional },
520     { WM_WINDOWPOSCHANGED, sent },
521     { WM_MOVE, sent|defwinproc },
522     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
523     { WM_NCCALCSIZE, sent|optional },
524     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
525     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
526     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
527     { WM_NCACTIVATE, sent|wparam, 0 },
528     { WM_GETTEXT, sent|defwinproc|optional },
529     { WM_ACTIVATE, sent },
530     { WM_ACTIVATEAPP, sent|wparam, 0 },
531     { 0 }
532 };
533 /* ShowWindow(SW_HIDE) for a visible overlapped window */
534 static const struct message WmHideOverlappedSeq[] = {
535     { WM_SHOWWINDOW, sent|wparam, 0 },
536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
537     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
538     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
539     { WM_SIZE, sent|optional }, /* XP doesn't send it */
540     { WM_MOVE, sent|optional }, /* XP doesn't send it */
541     { WM_NCACTIVATE, sent|wparam, 0 },
542     { WM_ACTIVATE, sent|wparam, 0 },
543     { WM_ACTIVATEAPP, sent|wparam, 0 },
544     { WM_KILLFOCUS, sent|wparam, 0 },
545     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
546     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
547     { 0 }
548 };
549 /* DestroyWindow for a visible overlapped window */
550 static const struct message WmDestroyOverlappedSeq[] = {
551     { HCBT_DESTROYWND, hook },
552     { 0x0090, sent|optional },
553     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
554     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
555     { 0x0090, sent|optional },
556     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
557     { WM_NCACTIVATE, sent|wparam, 0 },
558     { WM_ACTIVATE, sent|wparam, 0 },
559     { WM_ACTIVATEAPP, sent|wparam, 0 },
560     { WM_KILLFOCUS, sent|wparam, 0 },
561     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
562     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
563     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
564     { WM_DESTROY, sent },
565     { WM_NCDESTROY, sent },
566     { 0 }
567 };
568 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
569 static const struct message WmCreateMaxPopupSeq[] = {
570     { HCBT_CREATEWND, hook },
571     { WM_NCCREATE, sent },
572     { WM_NCCALCSIZE, sent|wparam, 0 },
573     { WM_CREATE, sent },
574     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
575     { WM_SIZE, sent|wparam, SIZE_RESTORED },
576     { WM_MOVE, sent },
577     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
578     { WM_GETMINMAXINFO, sent },
579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
580     { WM_NCCALCSIZE, sent|wparam, TRUE },
581     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
582     { WM_MOVE, sent|defwinproc },
583     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
584     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
585     { WM_SHOWWINDOW, sent|wparam, 1 },
586     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
587     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
588     { HCBT_ACTIVATE, hook },
589     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
590     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
591     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
592     { WM_ACTIVATEAPP, sent|wparam, 1 },
593     { WM_NCACTIVATE, sent|wparam, 1 },
594     { WM_ACTIVATE, sent|wparam, 1 },
595     { HCBT_SETFOCUS, hook },
596     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
597     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
598     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
599     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
600     { WM_SYNCPAINT, sent|wparam|optional, 4 },
601     { WM_NCPAINT, sent|wparam|optional, 1 },
602     { WM_ERASEBKGND, sent|optional },
603     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
604     { 0 }
605 };
606 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
607 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
608     { HCBT_CREATEWND, hook },
609     { WM_NCCREATE, sent },
610     { WM_NCCALCSIZE, sent|wparam, 0 },
611     { WM_CREATE, sent },
612     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
613     { WM_SIZE, sent|wparam, SIZE_RESTORED },
614     { WM_MOVE, sent },
615     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
616     { WM_GETMINMAXINFO, sent },
617     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
618     { WM_NCCALCSIZE, sent|wparam, TRUE },
619     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
620     { WM_MOVE, sent|defwinproc },
621     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
622     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
623     { 0 }
624 };
625 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
626 static const struct message WmShowMaxPopupResizedSeq[] = {
627     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
628     { WM_GETMINMAXINFO, sent },
629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
630     { WM_NCCALCSIZE, sent|wparam, TRUE },
631     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
632     { HCBT_ACTIVATE, hook },
633     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
634     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
635     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
636     { WM_ACTIVATEAPP, sent|wparam, 1 },
637     { WM_NCACTIVATE, sent|wparam, 1 },
638     { WM_ACTIVATE, sent|wparam, 1 },
639     { HCBT_SETFOCUS, hook },
640     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
641     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
642     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
643     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
644     { WM_NCPAINT, sent|wparam|optional, 1 },
645     { WM_ERASEBKGND, sent|optional },
646     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
647     /* WinNT4.0 sends WM_MOVE */
648     { WM_MOVE, sent|defwinproc|optional },
649     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
650     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
651     { 0 }
652 };
653 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
654 static const struct message WmShowMaxPopupSeq[] = {
655     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
656     { WM_GETMINMAXINFO, sent },
657     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
658     { WM_NCCALCSIZE, sent|wparam, TRUE },
659     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
660     { HCBT_ACTIVATE, hook },
661     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
662     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
663     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
664     { WM_ACTIVATEAPP, sent|wparam, 1 },
665     { WM_NCACTIVATE, sent|wparam, 1 },
666     { WM_ACTIVATE, sent|wparam, 1 },
667     { HCBT_SETFOCUS, hook },
668     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
669     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
670     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
671     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
672     { WM_SYNCPAINT, sent|wparam|optional, 4 },
673     { WM_NCPAINT, sent|wparam|optional, 1 },
674     { WM_ERASEBKGND, sent|optional },
675     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
676     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
677     { 0 }
678 };
679 /* CreateWindow(WS_VISIBLE) for popup window */
680 static const struct message WmCreatePopupSeq[] = {
681     { HCBT_CREATEWND, hook },
682     { WM_NCCREATE, sent },
683     { WM_NCCALCSIZE, sent|wparam, 0 },
684     { WM_CREATE, sent },
685     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
686     { WM_SIZE, sent|wparam, SIZE_RESTORED },
687     { WM_MOVE, sent },
688     { WM_SHOWWINDOW, sent|wparam, 1 },
689     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
690     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
691     { HCBT_ACTIVATE, hook },
692     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
693     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
694     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
695     { WM_NCPAINT, sent|wparam|optional, 1 },
696     { WM_ERASEBKGND, sent|optional },
697     { WM_ACTIVATEAPP, sent|wparam, 1 },
698     { WM_NCACTIVATE, sent|wparam, 1 },
699     { WM_ACTIVATE, sent|wparam, 1 },
700     { HCBT_SETFOCUS, hook },
701     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
702     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
703     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
704     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
705     { WM_SYNCPAINT, sent|wparam|optional, 4 },
706     { WM_NCPAINT, sent|wparam|optional, 1 },
707     { WM_ERASEBKGND, sent|optional },
708     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
709     { 0 }
710 };
711 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
712 static const struct message WmShowVisMaxPopupSeq[] = {
713     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
714     { WM_GETMINMAXINFO, sent },
715     { WM_GETTEXT, sent|optional },
716     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
717     { WM_NCCALCSIZE, sent|wparam, TRUE },
718     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
719     { WM_NCPAINT, sent|wparam|optional, 1 },
720     { WM_ERASEBKGND, sent|optional },
721     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
722     { WM_MOVE, sent|defwinproc },
723     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
724     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
725     { 0 }
726 };
727 /* CreateWindow (for a child popup window, not initially visible) */
728 static const struct message WmCreateChildPopupSeq[] = {
729     { HCBT_CREATEWND, hook },
730     { WM_NCCREATE, sent }, 
731     { WM_NCCALCSIZE, sent|wparam, 0 },
732     { WM_CREATE, sent },
733     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
734     { WM_SIZE, sent|wparam, SIZE_RESTORED },
735     { WM_MOVE, sent },
736     { 0 }
737 };
738 /* CreateWindow (for a popup window, not initially visible,
739  * which sets WS_VISIBLE in WM_CREATE handler)
740  */
741 static const struct message WmCreateInvisiblePopupSeq[] = {
742     { HCBT_CREATEWND, hook },
743     { WM_NCCREATE, sent }, 
744     { WM_NCCALCSIZE, sent|wparam, 0 },
745     { WM_CREATE, sent },
746     { WM_STYLECHANGING, sent },
747     { WM_STYLECHANGED, sent },
748     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
749     { WM_SIZE, sent|wparam, SIZE_RESTORED },
750     { WM_MOVE, sent },
751     { 0 }
752 };
753 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
754  * for a popup window with WS_VISIBLE style set
755  */
756 static const struct message WmShowVisiblePopupSeq_2[] = {
757     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
758     { 0 }
759 };
760 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
761  * for a popup window with WS_VISIBLE style set
762  */
763 static const struct message WmShowVisiblePopupSeq_3[] = {
764     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
765     { HCBT_ACTIVATE, hook },
766     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
767     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
768     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
769     { WM_NCACTIVATE, sent|wparam, 1 },
770     { WM_ACTIVATE, sent|wparam, 1 },
771     { HCBT_SETFOCUS, hook },
772     { WM_KILLFOCUS, sent|parent },
773     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
774     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
775     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
776     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
777     { WM_SETFOCUS, sent|defwinproc },
778     { 0 }
779 };
780 /* CreateWindow (for child window, not initially visible) */
781 static const struct message WmCreateChildSeq[] = {
782     { HCBT_CREATEWND, hook },
783     { WM_NCCREATE, sent }, 
784     /* child is inserted into parent's child list after WM_NCCREATE returns */
785     { WM_NCCALCSIZE, sent|wparam, 0 },
786     { WM_CREATE, sent },
787     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
788     { WM_SIZE, sent|wparam, SIZE_RESTORED },
789     { WM_MOVE, sent },
790     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
791     { 0 }
792 };
793 /* CreateWindow (for maximized child window, not initially visible) */
794 static const struct message WmCreateMaximizedChildSeq[] = {
795     { HCBT_CREATEWND, hook },
796     { WM_NCCREATE, sent }, 
797     { WM_NCCALCSIZE, sent|wparam, 0 },
798     { WM_CREATE, sent },
799     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
800     { WM_SIZE, sent|wparam, SIZE_RESTORED },
801     { WM_MOVE, sent },
802     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
803     { WM_GETMINMAXINFO, sent },
804     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
805     { WM_NCCALCSIZE, sent|wparam, 1 },
806     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
807     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
808     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
809     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
810     { 0 }
811 };
812 /* CreateWindow (for a child window, initially visible) */
813 static const struct message WmCreateVisibleChildSeq[] = {
814     { HCBT_CREATEWND, hook },
815     { WM_NCCREATE, sent }, 
816     /* child is inserted into parent's child list after WM_NCCREATE returns */
817     { WM_NCCALCSIZE, sent|wparam, 0 },
818     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
819     { WM_CREATE, sent },
820     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
821     { WM_SIZE, sent|wparam, SIZE_RESTORED },
822     { WM_MOVE, sent },
823     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
824     { WM_SHOWWINDOW, sent|wparam, 1 },
825     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
826     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
827     { WM_ERASEBKGND, sent|parent|optional },
828     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
829     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
830     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
831     { 0 }
832 };
833 /* ShowWindow(SW_SHOW) for a not visible child window */
834 static const struct message WmShowChildSeq[] = {
835     { WM_SHOWWINDOW, sent|wparam, 1 },
836     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
837     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
838     { WM_ERASEBKGND, sent|parent|optional },
839     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
840     { 0 }
841 };
842 /* ShowWindow(SW_HIDE) for a visible child window */
843 static const struct message WmHideChildSeq[] = {
844     { WM_SHOWWINDOW, sent|wparam, 0 },
845     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
846     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
847     { WM_ERASEBKGND, sent|parent|optional },
848     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
849     { 0 }
850 };
851 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
852 static const struct message WmHideChildSeq2[] = {
853     { WM_SHOWWINDOW, sent|wparam, 0 },
854     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
855     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
856     { WM_ERASEBKGND, sent|parent },
857     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
858     { 0 }
859 };
860 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
861  * for a not visible child window
862  */
863 static const struct message WmShowChildSeq_2[] = {
864     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
865     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
866     { WM_CHILDACTIVATE, sent },
867     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
868     { 0 }
869 };
870 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
871  * for a not visible child window
872  */
873 static const struct message WmShowChildSeq_3[] = {
874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
875     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
876     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
877     { 0 }
878 };
879 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
880  * for a visible child window with a caption
881  */
882 static const struct message WmShowChildSeq_4[] = {
883     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
884     { WM_CHILDACTIVATE, sent },
885     { 0 }
886 };
887 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
888 static const struct message WmShowChildInvisibleParentSeq_1[] = {
889     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
890     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
891     { WM_NCCALCSIZE, sent|wparam, 1 },
892     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
893     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
894     { WM_MOVE, sent|defwinproc },
895     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
896     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
897     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
898     /* FIXME: Wine creates an icon/title window while Windows doesn't */
899     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
900     { WM_GETTEXT, sent|optional },
901     { 0 }
902 };
903 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
904 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
905     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
906     { 0 }
907 };
908 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
909 static const struct message WmShowChildInvisibleParentSeq_2[] = {
910     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
911     { WM_GETMINMAXINFO, sent },
912     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
913     { WM_NCCALCSIZE, sent|wparam, 1 },
914     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
915     { WM_CHILDACTIVATE, sent },
916     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
917     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
918     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
919     { 0 }
920 };
921 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
922 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
923     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
924     { 0 }
925 };
926 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
927 static const struct message WmShowChildInvisibleParentSeq_3[] = {
928     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
929     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
930     { WM_NCCALCSIZE, sent|wparam, 1 },
931     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
932     { WM_CHILDACTIVATE, sent },
933     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
934     { WM_MOVE, sent|defwinproc },
935     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
936     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
937     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
938     /* FIXME: Wine creates an icon/title window while Windows doesn't */
939     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
940     { WM_GETTEXT, sent|optional },
941     { 0 }
942 };
943 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
944 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
945     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
946     { 0 }
947 };
948 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
949 static const struct message WmShowChildInvisibleParentSeq_4[] = {
950     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
952     { WM_NCCALCSIZE, sent|wparam, 1 },
953     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
954     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
955     { WM_MOVE, sent|defwinproc },
956     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
957     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
958     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
959     /* FIXME: Wine creates an icon/title window while Windows doesn't */
960     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
961     { WM_GETTEXT, sent|optional },
962     { 0 }
963 };
964 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
965 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
966     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
967     { 0 }
968 };
969 /* ShowWindow(SW_SHOW) for child with invisible parent */
970 static const struct message WmShowChildInvisibleParentSeq_5[] = {
971     { WM_SHOWWINDOW, sent|wparam, 1 },
972     { 0 }
973 };
974 /* ShowWindow(SW_HIDE) for child with invisible parent */
975 static const struct message WmHideChildInvisibleParentSeq[] = {
976     { WM_SHOWWINDOW, sent|wparam, 0 },
977     { 0 }
978 };
979 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
980 static const struct message WmShowChildInvisibleParentSeq_6[] = {
981     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
982     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
983     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
984     { 0 }
985 };
986 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
987 static const struct message WmHideChildInvisibleParentSeq_2[] = {
988     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
989     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
990     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
991     { 0 }
992 };
993 /* DestroyWindow for a visible child window */
994 static const struct message WmDestroyChildSeq[] = {
995     { HCBT_DESTROYWND, hook },
996     { 0x0090, sent|optional },
997     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
998     { WM_SHOWWINDOW, sent|wparam, 0 },
999     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1000     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1001     { WM_ERASEBKGND, sent|parent|optional },
1002     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1003     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1004     { WM_KILLFOCUS, sent },
1005     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1006     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1007     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1008     { WM_SETFOCUS, sent|parent },
1009     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1010     { WM_DESTROY, sent },
1011     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1012     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1013     { WM_NCDESTROY, sent },
1014     { 0 }
1015 };
1016 /* DestroyWindow for a visible child window with invisible parent */
1017 static const struct message WmDestroyInvisibleChildSeq[] = {
1018     { HCBT_DESTROYWND, hook },
1019     { 0x0090, sent|optional },
1020     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1021     { WM_SHOWWINDOW, sent|wparam, 0 },
1022     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1023     { WM_DESTROY, sent },
1024     { WM_NCDESTROY, sent },
1025     { 0 }
1026 };
1027 /* Moving the mouse in nonclient area */
1028 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1029     { WM_NCHITTEST, sent },
1030     { WM_SETCURSOR, sent },
1031     { WM_NCMOUSEMOVE, posted },
1032     { 0 }
1033 };
1034 /* Moving the mouse in client area */
1035 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1036     { WM_NCHITTEST, sent },
1037     { WM_SETCURSOR, sent },
1038     { WM_MOUSEMOVE, posted },
1039     { 0 }
1040 };
1041 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1042 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1043     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1044     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1045     { WM_GETMINMAXINFO, sent|defwinproc },
1046     { WM_ENTERSIZEMOVE, sent|defwinproc },
1047     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1048     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1049     { WM_MOVE, sent|defwinproc },
1050     { WM_EXITSIZEMOVE, sent|defwinproc },
1051     { 0 }
1052 };
1053 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1054 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1055     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1056     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1057     { WM_GETMINMAXINFO, sent|defwinproc },
1058     { WM_ENTERSIZEMOVE, sent|defwinproc },
1059     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1060     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1061     { WM_GETMINMAXINFO, sent|defwinproc },
1062     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1063     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1064     { WM_GETTEXT, sent|defwinproc },
1065     { WM_ERASEBKGND, sent|defwinproc },
1066     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1067     { WM_MOVE, sent|defwinproc },
1068     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1069     { WM_EXITSIZEMOVE, sent|defwinproc },
1070     { 0 }
1071 };
1072 /* Resizing child window with MoveWindow (32) */
1073 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1074     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1075     { WM_NCCALCSIZE, sent|wparam, 1 },
1076     { WM_ERASEBKGND, sent|parent|optional },
1077     { WM_ERASEBKGND, sent|optional },
1078     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1079     { WM_MOVE, sent|defwinproc },
1080     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1081     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1082     { 0 }
1083 };
1084 /* Clicking on inactive button */
1085 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1086     { WM_NCHITTEST, sent },
1087     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1088     { WM_MOUSEACTIVATE, sent },
1089     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1090     { WM_SETCURSOR, sent },
1091     { WM_SETCURSOR, sent|parent|defwinproc },
1092     { WM_LBUTTONDOWN, posted },
1093     { WM_KILLFOCUS, posted|parent },
1094     { WM_SETFOCUS, posted },
1095     { WM_CTLCOLORBTN, posted|parent },
1096     { BM_SETSTATE, posted },
1097     { WM_CTLCOLORBTN, posted|parent },
1098     { WM_LBUTTONUP, posted },
1099     { BM_SETSTATE, posted },
1100     { WM_CTLCOLORBTN, posted|parent },
1101     { WM_COMMAND, posted|parent },
1102     { 0 }
1103 };
1104 /* Reparenting a button (16/32) */
1105 /* The last child (button) reparented gets topmost for its new parent. */
1106 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1107     { WM_SHOWWINDOW, sent|wparam, 0 },
1108     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1109     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1110     { WM_ERASEBKGND, sent|parent },
1111     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1112     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1113     { WM_CHILDACTIVATE, sent },
1114     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1115     { WM_MOVE, sent|defwinproc },
1116     { WM_SHOWWINDOW, sent|wparam, 1 },
1117     { 0 }
1118 };
1119 /* Creation of a custom dialog (32) */
1120 static const struct message WmCreateCustomDialogSeq[] = {
1121     { HCBT_CREATEWND, hook },
1122     { WM_GETMINMAXINFO, sent },
1123     { WM_NCCREATE, sent },
1124     { WM_NCCALCSIZE, sent|wparam, 0 },
1125     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1126     { WM_CREATE, sent },
1127     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1128     { WM_SHOWWINDOW, sent|wparam, 1 },
1129     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1130     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1131     { HCBT_ACTIVATE, hook },
1132     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1133
1134
1135     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1136
1137     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1138
1139     { WM_NCACTIVATE, sent|wparam, 1 },
1140     { WM_GETTEXT, sent|optional|defwinproc },
1141     { WM_GETTEXT, sent|optional|defwinproc },
1142     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1143     { WM_ACTIVATE, sent|wparam, 1 },
1144     { WM_KILLFOCUS, sent|parent },
1145     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1146     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1147     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1148     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1149     { WM_SETFOCUS, sent },
1150     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1151     { WM_NCPAINT, sent|wparam, 1 },
1152     { WM_GETTEXT, sent|optional|defwinproc },
1153     { WM_GETTEXT, sent|optional|defwinproc },
1154     { WM_ERASEBKGND, sent },
1155     { WM_CTLCOLORDLG, sent|defwinproc },
1156     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1157     { WM_GETTEXT, sent|optional },
1158     { WM_GETTEXT, sent|optional },
1159     { WM_NCCALCSIZE, sent|optional },
1160     { WM_NCPAINT, sent|optional },
1161     { WM_GETTEXT, sent|optional|defwinproc },
1162     { WM_GETTEXT, sent|optional|defwinproc },
1163     { WM_ERASEBKGND, sent|optional },
1164     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1165     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1166     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1167     { WM_MOVE, sent },
1168     { 0 }
1169 };
1170 /* Calling EndDialog for a custom dialog (32) */
1171 static const struct message WmEndCustomDialogSeq[] = {
1172     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1173     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1174     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1175     { WM_GETTEXT, sent|optional },
1176     { HCBT_ACTIVATE, hook },
1177     { WM_NCACTIVATE, sent|wparam, 0 },
1178     { WM_GETTEXT, sent|optional|defwinproc },
1179     { WM_GETTEXT, sent|optional|defwinproc },
1180     { WM_ACTIVATE, sent|wparam, 0 },
1181     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1182     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1183     { HCBT_SETFOCUS, hook },
1184     { WM_KILLFOCUS, sent },
1185     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1186     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1187     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1188     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1189     { WM_SETFOCUS, sent|parent|defwinproc },
1190     { 0 }
1191 };
1192 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1193 static const struct message WmShowCustomDialogSeq[] = {
1194     { WM_SHOWWINDOW, sent|wparam, 1 },
1195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1196     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1197     { HCBT_ACTIVATE, hook },
1198     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1199
1200     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1201
1202     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1203     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1204     { WM_NCACTIVATE, sent|wparam, 1 },
1205     { WM_ACTIVATE, sent|wparam, 1 },
1206
1207     { WM_KILLFOCUS, sent|parent },
1208     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1209     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1210     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1211     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1212     { WM_SETFOCUS, sent },
1213     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1214     { WM_NCPAINT, sent|wparam, 1 },
1215     { WM_ERASEBKGND, sent },
1216     { WM_CTLCOLORDLG, sent|defwinproc },
1217     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1218     { 0 }
1219 };
1220 /* Creation and destruction of a modal dialog (32) */
1221 static const struct message WmModalDialogSeq[] = {
1222     { WM_CANCELMODE, sent|parent },
1223     { HCBT_SETFOCUS, hook },
1224     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1225     { WM_KILLFOCUS, sent|parent },
1226     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1227     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1228     { WM_ENABLE, sent|parent|wparam, 0 },
1229     { HCBT_CREATEWND, hook },
1230     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1231     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1232     { WM_SETFONT, sent },
1233     { WM_INITDIALOG, sent },
1234     { WM_CHANGEUISTATE, sent|optional },
1235     { WM_UPDATEUISTATE, sent|optional },
1236     { WM_SHOWWINDOW, sent },
1237     { HCBT_ACTIVATE, hook },
1238     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1239     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1240     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1241     { WM_NCACTIVATE, sent|wparam, 1 },
1242     { WM_GETTEXT, sent|optional },
1243     { WM_ACTIVATE, sent|wparam, 1 },
1244     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1245     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1246     { WM_NCPAINT, sent },
1247     { WM_GETTEXT, sent|optional },
1248     { WM_ERASEBKGND, sent },
1249     { WM_CTLCOLORDLG, sent },
1250     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1251     { WM_GETTEXT, sent|optional },
1252     { WM_NCCALCSIZE, sent|optional },
1253     { WM_NCPAINT, sent|optional },
1254     { WM_GETTEXT, sent|optional },
1255     { WM_ERASEBKGND, sent|optional },
1256     { WM_CTLCOLORDLG, sent|optional },
1257     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1258     { WM_PAINT, sent|optional },
1259     { WM_CTLCOLORBTN, sent },
1260     { WM_ENTERIDLE, sent|parent|optional },
1261     { WM_ENTERIDLE, sent|parent|optional },
1262     { WM_ENTERIDLE, sent|parent|optional },
1263     { WM_ENTERIDLE, sent|parent|optional },
1264     { WM_ENTERIDLE, sent|parent|optional },
1265     { WM_ENTERIDLE, sent|parent|optional },
1266     { WM_ENTERIDLE, sent|parent|optional },
1267     { WM_ENTERIDLE, sent|parent|optional },
1268     { WM_ENTERIDLE, sent|parent|optional },
1269     { WM_ENTERIDLE, sent|parent|optional },
1270     { WM_ENTERIDLE, sent|parent|optional },
1271     { WM_ENTERIDLE, sent|parent|optional },
1272     { WM_ENTERIDLE, sent|parent|optional },
1273     { WM_ENTERIDLE, sent|parent|optional },
1274     { WM_ENTERIDLE, sent|parent|optional },
1275     { WM_ENTERIDLE, sent|parent|optional },
1276     { WM_ENTERIDLE, sent|parent|optional },
1277     { WM_ENTERIDLE, sent|parent|optional },
1278     { WM_ENTERIDLE, sent|parent|optional },
1279     { WM_ENTERIDLE, sent|parent|optional },
1280     { WM_TIMER, sent },
1281     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1282     { WM_ENABLE, sent|parent|wparam, 1 },
1283     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1284     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1285     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1286     { WM_GETTEXT, sent|optional },
1287     { HCBT_ACTIVATE, hook },
1288     { WM_NCACTIVATE, sent|wparam, 0 },
1289     { WM_GETTEXT, sent|optional },
1290     { WM_ACTIVATE, sent|wparam, 0 },
1291     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1292     { WM_WINDOWPOSCHANGING, sent|optional },
1293     { HCBT_SETFOCUS, hook },
1294     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1295     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1296     { WM_SETFOCUS, sent|parent|defwinproc },
1297     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1298     { HCBT_DESTROYWND, hook },
1299     { 0x0090, sent|optional },
1300     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1301     { WM_DESTROY, sent },
1302     { WM_NCDESTROY, sent },
1303     { 0 }
1304 };
1305 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1306 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1307     /* (inside dialog proc, handling WM_INITDIALOG) */
1308     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1309     { WM_NCCALCSIZE, sent },
1310     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1311     { WM_GETTEXT, sent|defwinproc },
1312     { WM_ACTIVATE, sent|parent|wparam, 0 },
1313     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1314     { WM_WINDOWPOSCHANGING, sent|parent },
1315     { WM_NCACTIVATE, sent|wparam, 1 },
1316     { WM_ACTIVATE, sent|wparam, 1 },
1317     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1318     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1319     /* (setting focus) */
1320     { WM_SHOWWINDOW, sent|wparam, 1 },
1321     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1322     { WM_NCPAINT, sent },
1323     { WM_GETTEXT, sent|defwinproc },
1324     { WM_ERASEBKGND, sent },
1325     { WM_CTLCOLORDLG, sent|defwinproc },
1326     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1327     { WM_PAINT, sent },
1328     /* (bunch of WM_CTLCOLOR* for each control) */
1329     { WM_PAINT, sent|parent },
1330     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1331     { WM_SETCURSOR, sent|parent },
1332     { 0 }
1333 };
1334 /* SetMenu for NonVisible windows with size change*/
1335 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1336     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1337     { WM_NCCALCSIZE, sent|wparam, 1 },
1338     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1339     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1340     { WM_MOVE, sent|defwinproc },
1341     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1342     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1343     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1344     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1345     { WM_GETTEXT, sent|optional },
1346     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1347     { 0 }
1348 };
1349 /* SetMenu for NonVisible windows with no size change */
1350 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1351     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1352     { WM_NCCALCSIZE, sent|wparam, 1 },
1353     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1354     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1355     { 0 }
1356 };
1357 /* SetMenu for Visible windows with size change */
1358 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1359     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1360     { WM_NCCALCSIZE, sent|wparam, 1 },
1361     { 0x0093, sent|defwinproc|optional },
1362     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1363     { WM_NCPAINT, sent }, /* wparam != 1 */
1364     { 0x0093, sent|defwinproc|optional },
1365     { 0x0093, sent|defwinproc|optional },
1366     { 0x0091, sent|defwinproc|optional },
1367     { 0x0092, sent|defwinproc|optional },
1368     { WM_GETTEXT, sent|defwinproc|optional },
1369     { WM_ERASEBKGND, sent|optional },
1370     { WM_ACTIVATE, sent|optional },
1371     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1372     { WM_MOVE, sent|defwinproc },
1373     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1374     { 0x0093, sent|optional },
1375     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1376     { 0x0093, sent|defwinproc|optional },
1377     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1378     { 0x0093, sent|defwinproc|optional },
1379     { 0x0093, sent|defwinproc|optional },
1380     { 0x0091, sent|defwinproc|optional },
1381     { 0x0092, sent|defwinproc|optional },
1382     { WM_ERASEBKGND, sent|optional },
1383     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1384     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1385     { 0 }
1386 };
1387 /* SetMenu for Visible windows with no size change */
1388 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1389     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1390     { WM_NCCALCSIZE, sent|wparam, 1 },
1391     { WM_NCPAINT, sent }, /* wparam != 1 */
1392     { WM_GETTEXT, sent|defwinproc|optional },
1393     { WM_ERASEBKGND, sent|optional },
1394     { WM_ACTIVATE, sent|optional },
1395     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1396     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1397     { 0 }
1398 };
1399 /* DrawMenuBar for a visible window */
1400 static const struct message WmDrawMenuBarSeq[] =
1401 {
1402     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1403     { WM_NCCALCSIZE, sent|wparam, 1 },
1404     { 0x0093, sent|defwinproc|optional },
1405     { WM_NCPAINT, sent }, /* wparam != 1 */
1406     { 0x0093, sent|defwinproc|optional },
1407     { 0x0093, sent|defwinproc|optional },
1408     { 0x0091, sent|defwinproc|optional },
1409     { 0x0092, sent|defwinproc|optional },
1410     { WM_GETTEXT, sent|defwinproc|optional },
1411     { WM_ERASEBKGND, sent|optional },
1412     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1413     { 0x0093, sent|optional },
1414     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1415     { 0 }
1416 };
1417
1418 static const struct message WmSetRedrawFalseSeq[] =
1419 {
1420     { WM_SETREDRAW, sent|wparam, 0 },
1421     { 0 }
1422 };
1423
1424 static const struct message WmSetRedrawTrueSeq[] =
1425 {
1426     { WM_SETREDRAW, sent|wparam, 1 },
1427     { 0 }
1428 };
1429
1430 static const struct message WmEnableWindowSeq_1[] =
1431 {
1432     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1433     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1434     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1435     { 0 }
1436 };
1437
1438 static const struct message WmEnableWindowSeq_2[] =
1439 {
1440     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1441     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1442     { 0 }
1443 };
1444
1445 static const struct message WmGetScrollRangeSeq[] =
1446 {
1447     { SBM_GETRANGE, sent },
1448     { 0 }
1449 };
1450 static const struct message WmGetScrollInfoSeq[] =
1451 {
1452     { SBM_GETSCROLLINFO, sent },
1453     { 0 }
1454 };
1455 static const struct message WmSetScrollRangeSeq[] =
1456 {
1457     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1458        sends SBM_SETSCROLLINFO.
1459      */
1460     { SBM_SETSCROLLINFO, sent },
1461     { 0 }
1462 };
1463 /* SetScrollRange for a window without a non-client area */
1464 static const struct message WmSetScrollRangeHSeq_empty[] =
1465 {
1466     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1467     { 0 }
1468 };
1469 static const struct message WmSetScrollRangeVSeq_empty[] =
1470 {
1471     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1472     { 0 }
1473 };
1474 static const struct message WmSetScrollRangeHVSeq[] =
1475 {
1476     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1477     { WM_NCCALCSIZE, sent|wparam, 1 },
1478     { WM_GETTEXT, sent|defwinproc|optional },
1479     { WM_ERASEBKGND, sent|optional },
1480     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1481     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1482     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1483     { 0 }
1484 };
1485 /* SetScrollRange for a window with a non-client area */
1486 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1487 {
1488     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1489     { WM_NCCALCSIZE, sent|wparam, 1 },
1490     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1491     { WM_NCPAINT, sent|optional },
1492     { WM_STYLECHANGING, sent|defwinproc|optional },
1493     { WM_STYLECHANGED, sent|defwinproc|optional },
1494     { WM_STYLECHANGING, sent|defwinproc|optional },
1495     { WM_STYLECHANGED, sent|defwinproc|optional },
1496     { WM_STYLECHANGING, sent|defwinproc|optional },
1497     { WM_STYLECHANGED, sent|defwinproc|optional },
1498     { WM_STYLECHANGING, sent|defwinproc|optional },
1499     { WM_STYLECHANGED, sent|defwinproc|optional },
1500     { WM_GETTEXT, sent|defwinproc|optional },
1501     { WM_GETTEXT, sent|defwinproc|optional },
1502     { WM_ERASEBKGND, sent|optional },
1503     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1504     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1505     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1506     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1507     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1508     { WM_GETTEXT, sent|optional },
1509     { WM_GETTEXT, sent|optional },
1510     { WM_GETTEXT, sent|optional },
1511     { WM_GETTEXT, sent|optional },
1512     { 0 }
1513 };
1514 /* test if we receive the right sequence of messages */
1515 /* after calling ShowWindow( SW_SHOWNA) */
1516 static const struct message WmSHOWNAChildInvisParInvis[] = {
1517     { WM_SHOWWINDOW, sent|wparam, 1 },
1518     { 0 }
1519 };
1520 static const struct message WmSHOWNAChildVisParInvis[] = {
1521     { WM_SHOWWINDOW, sent|wparam, 1 },
1522     { 0 }
1523 };
1524 static const struct message WmSHOWNAChildVisParVis[] = {
1525     { WM_SHOWWINDOW, sent|wparam, 1 },
1526     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1527     { 0 }
1528 };
1529 static const struct message WmSHOWNAChildInvisParVis[] = {
1530     { WM_SHOWWINDOW, sent|wparam, 1 },
1531     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1532     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1533     { WM_ERASEBKGND, sent|optional },
1534     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1535     { 0 }
1536 };
1537 static const struct message WmSHOWNATopVisible[] = {
1538     { WM_SHOWWINDOW, sent|wparam, 1 },
1539     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1540     { 0 }
1541 };
1542 static const struct message WmSHOWNATopInvisible[] = {
1543     { WM_SHOWWINDOW, sent|wparam, 1 },
1544     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1545     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1546     { WM_NCPAINT, sent|wparam, 1 },
1547     { WM_GETTEXT, sent|defwinproc|optional },
1548     { WM_ERASEBKGND, sent|optional },
1549     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1550     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1551     { WM_NCPAINT, sent|wparam|optional, 1 },
1552     { WM_ERASEBKGND, sent|optional },
1553     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1554     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1555     { WM_MOVE, sent },
1556     { 0 }
1557 };
1558
1559 static int after_end_dialog, test_def_id;
1560 static int sequence_cnt, sequence_size;
1561 static struct message* sequence;
1562 static int log_all_parent_messages;
1563
1564 /* user32 functions */
1565 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1566 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1567 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1568 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1569 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1570 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1571 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1572 /* kernel32 functions */
1573 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1574
1575 static void init_procs(void)
1576 {
1577     HMODULE user32 = GetModuleHandleA("user32.dll");
1578     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1579
1580 #define GET_PROC(dll, func) \
1581     p ## func = (void*)GetProcAddress(dll, #func); \
1582     if(!p ## func) { \
1583       trace("GetProcAddress(%s) failed\n", #func); \
1584     }
1585
1586     GET_PROC(user32, GetAncestor)
1587     GET_PROC(user32, GetMenuInfo)
1588     GET_PROC(user32, NotifyWinEvent)
1589     GET_PROC(user32, SetMenuInfo)
1590     GET_PROC(user32, SetWinEventHook)
1591     GET_PROC(user32, TrackMouseEvent)
1592     GET_PROC(user32, UnhookWinEvent)
1593
1594     GET_PROC(kernel32, GetCPInfoExA)
1595
1596 #undef GET_PROC
1597 }
1598
1599 static void add_message(const struct message *msg)
1600 {
1601     if (!sequence) 
1602     {
1603         sequence_size = 10;
1604         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1605     }
1606     if (sequence_cnt == sequence_size) 
1607     {
1608         sequence_size *= 2;
1609         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1610     }
1611     assert(sequence);
1612
1613     sequence[sequence_cnt].message = msg->message;
1614     sequence[sequence_cnt].flags = msg->flags;
1615     sequence[sequence_cnt].wParam = msg->wParam;
1616     sequence[sequence_cnt].lParam = msg->lParam;
1617
1618     sequence_cnt++;
1619 }
1620
1621 /* try to make sure pending X events have been processed before continuing */
1622 static void flush_events(void)
1623 {
1624     MSG msg;
1625     int diff = 200;
1626     int min_timeout = 50;
1627     DWORD time = GetTickCount() + diff;
1628
1629     while (diff > 0)
1630     {
1631         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1632         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1633         diff = time - GetTickCount();
1634         min_timeout = 10;
1635     }
1636 }
1637
1638 static void flush_sequence(void)
1639 {
1640     HeapFree(GetProcessHeap(), 0, sequence);
1641     sequence = 0;
1642     sequence_cnt = sequence_size = 0;
1643 }
1644
1645 #define ok_sequence( exp, contx, todo) \
1646         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1647
1648
1649 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1650         const char *file, int line)
1651 {
1652     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1653     const struct message *actual;
1654     int failcount = 0;
1655     
1656     add_message(&end_of_sequence);
1657
1658     actual = sequence;
1659
1660     while (expected->message && actual->message)
1661     {
1662         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1663
1664         if (expected->message == actual->message)
1665         {
1666             if (expected->flags & wparam)
1667             {
1668                 if (expected->wParam != actual->wParam && todo)
1669                 {
1670                     todo_wine {
1671                         failcount ++;
1672                         ok_( file, line) (FALSE,
1673                             "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1674                             context, expected->message, expected->wParam, actual->wParam);
1675                     }
1676                 }
1677                 else
1678                 ok_( file, line) (expected->wParam == actual->wParam,
1679                      "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1680                      context, expected->message, expected->wParam, actual->wParam);
1681             }
1682             if (expected->flags & lparam)
1683             {
1684                 if (expected->lParam != actual->lParam && todo)
1685                 {
1686                     todo_wine {
1687                         failcount ++;
1688                         ok_( file, line) (FALSE,
1689                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1690                             context, expected->message, expected->lParam, actual->lParam);
1691                     }
1692                 }
1693                 else
1694                  ok_( file, line) (expected->lParam == actual->lParam,
1695                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1696                      context, expected->message, expected->lParam, actual->lParam);
1697             }
1698             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1699             {
1700                     todo_wine {
1701                         failcount ++;
1702                         ok_( file, line) (FALSE,
1703                             "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1704                             context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1705                     }
1706             }
1707             else
1708                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1709                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1710                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1711             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1712                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1713                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1714             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1715                 "%s: the msg 0x%04x should have been %s\n",
1716                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1717             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1718                 "%s: the msg 0x%04x was expected in %s\n",
1719                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1720             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1721                 "%s: the msg 0x%04x should have been sent by a hook\n",
1722                 context, expected->message);
1723             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1724                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1725                 context, expected->message);
1726             expected++;
1727             actual++;
1728         }
1729         /* silently drop winevent messages if there is no support for them */
1730         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1731             expected++;
1732         else if (todo)
1733         {
1734             failcount++;
1735             todo_wine {
1736                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1737                     context, expected->message, actual->message);
1738             }
1739             flush_sequence();
1740             return;
1741         }
1742         else
1743         {
1744             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1745                 context, expected->message, actual->message);
1746             expected++;
1747             actual++;
1748         }
1749     }
1750
1751     /* skip all optional trailing messages */
1752     while (expected->message && ((expected->flags & optional) ||
1753             ((expected->flags & winevent_hook) && !hEvent_hook)))
1754         expected++;
1755
1756     if (todo)
1757     {
1758         todo_wine {
1759             if (expected->message || actual->message) {
1760                 failcount++;
1761                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1762                     context, expected->message, actual->message);
1763             }
1764         }
1765     }
1766     else
1767     {
1768         if (expected->message || actual->message)
1769             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1770                 context, expected->message, actual->message);
1771     }
1772     if( todo && !failcount) /* succeeded yet marked todo */
1773         todo_wine {
1774             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1775         }
1776
1777     flush_sequence();
1778 }
1779
1780 /******************************** MDI test **********************************/
1781
1782 /* CreateWindow for MDI frame window, initially visible */
1783 static const struct message WmCreateMDIframeSeq[] = {
1784     { HCBT_CREATEWND, hook },
1785     { WM_GETMINMAXINFO, sent },
1786     { WM_NCCREATE, sent },
1787     { WM_NCCALCSIZE, sent|wparam, 0 },
1788     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1789     { WM_CREATE, sent },
1790     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1791     { WM_SHOWWINDOW, sent|wparam, 1 },
1792     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1793     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1794     { HCBT_ACTIVATE, hook },
1795     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1796     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1797     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1798     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1799     { WM_NCACTIVATE, sent|wparam, 1 },
1800     { WM_GETTEXT, sent|defwinproc|optional },
1801     { WM_ACTIVATE, sent|wparam, 1 },
1802     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1803     { HCBT_SETFOCUS, hook },
1804     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1805     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1806     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1807     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1808     /* Win9x adds SWP_NOZORDER below */
1809     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1810     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1811     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1812     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1813     { WM_MOVE, sent },
1814     { 0 }
1815 };
1816 /* DestroyWindow for MDI frame window, initially visible */
1817 static const struct message WmDestroyMDIframeSeq[] = {
1818     { HCBT_DESTROYWND, hook },
1819     { 0x0090, sent|optional },
1820     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1821     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1822     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1823     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1824     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1825     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1826     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1827     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1828     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1829     { WM_DESTROY, sent },
1830     { WM_NCDESTROY, sent },
1831     { 0 }
1832 };
1833 /* CreateWindow for MDI client window, initially visible */
1834 static const struct message WmCreateMDIclientSeq[] = {
1835     { HCBT_CREATEWND, hook },
1836     { WM_NCCREATE, sent },
1837     { WM_NCCALCSIZE, sent|wparam, 0 },
1838     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1839     { WM_CREATE, sent },
1840     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1841     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1842     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1843     { WM_MOVE, sent },
1844     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1845     { WM_SHOWWINDOW, sent|wparam, 1 },
1846     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1847     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1848     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1849     { 0 }
1850 };
1851 /* ShowWindow(SW_SHOW) for MDI client window */
1852 static const struct message WmShowMDIclientSeq[] = {
1853     { WM_SHOWWINDOW, sent|wparam, 1 },
1854     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1855     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1856     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1857     { 0 }
1858 };
1859 /* ShowWindow(SW_HIDE) for MDI client window */
1860 static const struct message WmHideMDIclientSeq[] = {
1861     { WM_SHOWWINDOW, sent|wparam, 0 },
1862     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1863     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1864     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1865     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1866     { 0 }
1867 };
1868 /* DestroyWindow for MDI client window, initially visible */
1869 static const struct message WmDestroyMDIclientSeq[] = {
1870     { HCBT_DESTROYWND, hook },
1871     { 0x0090, sent|optional },
1872     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1873     { WM_SHOWWINDOW, sent|wparam, 0 },
1874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1875     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1876     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1877     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1878     { WM_DESTROY, sent },
1879     { WM_NCDESTROY, sent },
1880     { 0 }
1881 };
1882 /* CreateWindow for MDI child window, initially visible */
1883 static const struct message WmCreateMDIchildVisibleSeq[] = {
1884     { HCBT_CREATEWND, hook },
1885     { WM_NCCREATE, sent }, 
1886     { WM_NCCALCSIZE, sent|wparam, 0 },
1887     { WM_CREATE, sent },
1888     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1889     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1890     { WM_MOVE, sent },
1891     /* Win2k sends wparam set to
1892      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1893      * while Win9x doesn't bother to set child window id according to
1894      * CLIENTCREATESTRUCT.idFirstChild
1895      */
1896     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1897     { WM_SHOWWINDOW, sent|wparam, 1 },
1898     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1899     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1900     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1901     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1902     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1903     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1904     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1905
1906     /* Win9x: message sequence terminates here. */
1907
1908     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1909     { HCBT_SETFOCUS, hook }, /* in MDI client */
1910     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1911     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1912     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1913     { WM_SETFOCUS, sent }, /* in MDI client */
1914     { HCBT_SETFOCUS, hook },
1915     { WM_KILLFOCUS, sent }, /* in MDI client */
1916     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1917     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1918     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1919     { WM_SETFOCUS, sent|defwinproc },
1920     { WM_MDIACTIVATE, sent|defwinproc },
1921     { 0 }
1922 };
1923 /* CreateWindow for MDI child window with invisible parent */
1924 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1925     { HCBT_CREATEWND, hook },
1926     { WM_GETMINMAXINFO, sent },
1927     { WM_NCCREATE, sent }, 
1928     { WM_NCCALCSIZE, sent|wparam, 0 },
1929     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1930     { WM_CREATE, sent },
1931     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1932     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1933     { WM_MOVE, sent },
1934     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1935     { WM_SHOWWINDOW, sent|wparam, 1 },
1936     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1937     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1938     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1939     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1940
1941     /* Win9x: message sequence terminates here. */
1942
1943     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1944     { HCBT_SETFOCUS, hook }, /* in MDI client */
1945     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1946     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1947     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1948     { WM_SETFOCUS, sent }, /* in MDI client */
1949     { HCBT_SETFOCUS, hook },
1950     { WM_KILLFOCUS, sent }, /* in MDI client */
1951     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1952     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1953     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1954     { WM_SETFOCUS, sent|defwinproc },
1955     { WM_MDIACTIVATE, sent|defwinproc },
1956     { 0 }
1957 };
1958 /* DestroyWindow for MDI child window, initially visible */
1959 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1960     { HCBT_DESTROYWND, hook },
1961     /* Win2k sends wparam set to
1962      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1963      * while Win9x doesn't bother to set child window id according to
1964      * CLIENTCREATESTRUCT.idFirstChild
1965      */
1966     { 0x0090, sent|optional },
1967     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1968     { WM_SHOWWINDOW, sent|wparam, 0 },
1969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1970     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1971     { WM_ERASEBKGND, sent|parent|optional },
1972     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1973
1974     /* { WM_DESTROY, sent }
1975      * Win9x: message sequence terminates here.
1976      */
1977
1978     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1979     { WM_KILLFOCUS, sent },
1980     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1981     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1982     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1983     { WM_SETFOCUS, sent }, /* in MDI client */
1984
1985     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1986     { WM_KILLFOCUS, sent }, /* in MDI client */
1987     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1988     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1989     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1990     { WM_SETFOCUS, sent }, /* in MDI client */
1991
1992     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1993
1994     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1995     { WM_KILLFOCUS, sent },
1996     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1997     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1998     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1999     { WM_SETFOCUS, sent }, /* in MDI client */
2000
2001     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2002     { WM_KILLFOCUS, sent }, /* in MDI client */
2003     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2004     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2005     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2006     { WM_SETFOCUS, sent }, /* in MDI client */
2007
2008     { WM_DESTROY, sent },
2009
2010     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2011     { WM_KILLFOCUS, sent },
2012     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2013     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2014     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2015     { WM_SETFOCUS, sent }, /* in MDI client */
2016
2017     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2018     { WM_KILLFOCUS, sent }, /* in MDI client */
2019     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2020     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2021     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2022     { WM_SETFOCUS, sent }, /* in MDI client */
2023
2024     { WM_NCDESTROY, sent },
2025     { 0 }
2026 };
2027 /* CreateWindow for MDI child window, initially invisible */
2028 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2029     { HCBT_CREATEWND, hook },
2030     { WM_NCCREATE, sent }, 
2031     { WM_NCCALCSIZE, sent|wparam, 0 },
2032     { WM_CREATE, sent },
2033     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2034     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2035     { WM_MOVE, sent },
2036     /* Win2k sends wparam set to
2037      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2038      * while Win9x doesn't bother to set child window id according to
2039      * CLIENTCREATESTRUCT.idFirstChild
2040      */
2041     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2042     { 0 }
2043 };
2044 /* DestroyWindow for MDI child window, initially invisible */
2045 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2046     { HCBT_DESTROYWND, hook },
2047     /* Win2k sends wparam set to
2048      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2049      * while Win9x doesn't bother to set child window id according to
2050      * CLIENTCREATESTRUCT.idFirstChild
2051      */
2052     { 0x0090, sent|optional },
2053     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2054     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2055     { WM_DESTROY, sent },
2056     { WM_NCDESTROY, sent },
2057     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2058     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2059     { 0 }
2060 };
2061 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2062 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2063     { HCBT_CREATEWND, hook },
2064     { WM_NCCREATE, sent }, 
2065     { WM_NCCALCSIZE, sent|wparam, 0 },
2066     { WM_CREATE, sent },
2067     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2068     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2069     { WM_MOVE, sent },
2070     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2071     { WM_GETMINMAXINFO, sent },
2072     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2073     { WM_NCCALCSIZE, sent|wparam, 1 },
2074     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2075     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2076      /* in MDI frame */
2077     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2078     { WM_NCCALCSIZE, sent|wparam, 1 },
2079     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2080     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2081     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2082     /* Win2k sends wparam set to
2083      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2084      * while Win9x doesn't bother to set child window id according to
2085      * CLIENTCREATESTRUCT.idFirstChild
2086      */
2087     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2088     { WM_SHOWWINDOW, sent|wparam, 1 },
2089     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2090     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2091     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2092     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2093     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2094     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2095     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2096
2097     /* Win9x: message sequence terminates here. */
2098
2099     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2100     { HCBT_SETFOCUS, hook }, /* in MDI client */
2101     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2102     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2103     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2104     { WM_SETFOCUS, sent }, /* in MDI client */
2105     { HCBT_SETFOCUS, hook },
2106     { WM_KILLFOCUS, sent }, /* in MDI client */
2107     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2108     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2109     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2110     { WM_SETFOCUS, sent|defwinproc },
2111     { WM_MDIACTIVATE, sent|defwinproc },
2112      /* in MDI frame */
2113     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2114     { WM_NCCALCSIZE, sent|wparam, 1 },
2115     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2116     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2117     { 0 }
2118 };
2119 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2120 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2121     /* restore the 1st MDI child */
2122     { WM_SETREDRAW, sent|wparam, 0 },
2123     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2124     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2125     { WM_NCCALCSIZE, sent|wparam, 1 },
2126     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2127     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2128     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2129      /* in MDI frame */
2130     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2131     { WM_NCCALCSIZE, sent|wparam, 1 },
2132     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2133     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2134     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2135     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2136     /* create the 2nd MDI child */
2137     { HCBT_CREATEWND, hook },
2138     { WM_NCCREATE, sent }, 
2139     { WM_NCCALCSIZE, sent|wparam, 0 },
2140     { WM_CREATE, sent },
2141     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2142     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2143     { WM_MOVE, sent },
2144     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2145     { WM_GETMINMAXINFO, sent },
2146     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2147     { WM_NCCALCSIZE, sent|wparam, 1 },
2148     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2150     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2151      /* in MDI frame */
2152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2153     { WM_NCCALCSIZE, sent|wparam, 1 },
2154     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2155     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2156     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2157     /* Win2k sends wparam set to
2158      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2159      * while Win9x doesn't bother to set child window id according to
2160      * CLIENTCREATESTRUCT.idFirstChild
2161      */
2162     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2163     { WM_SHOWWINDOW, sent|wparam, 1 },
2164     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2165     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2166     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2167     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2168     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2169     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2170
2171     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2172     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2173
2174     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2175
2176     /* Win9x: message sequence terminates here. */
2177
2178     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2179     { HCBT_SETFOCUS, hook },
2180     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
2181     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2182     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2183     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2184     { WM_SETFOCUS, sent }, /* in MDI client */
2185     { HCBT_SETFOCUS, hook },
2186     { WM_KILLFOCUS, sent }, /* in MDI client */
2187     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2188     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2189     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2190     { WM_SETFOCUS, sent|defwinproc },
2191
2192     { WM_MDIACTIVATE, sent|defwinproc },
2193      /* in MDI frame */
2194     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2195     { WM_NCCALCSIZE, sent|wparam, 1 },
2196     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2197     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2198     { 0 }
2199 };
2200 /* WM_MDICREATE MDI child window, initially visible and maximized */
2201 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2202     { WM_MDICREATE, sent },
2203     { HCBT_CREATEWND, hook },
2204     { WM_NCCREATE, sent }, 
2205     { WM_NCCALCSIZE, sent|wparam, 0 },
2206     { WM_CREATE, sent },
2207     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2208     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2209     { WM_MOVE, sent },
2210     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2211     { WM_GETMINMAXINFO, sent },
2212     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2213     { WM_NCCALCSIZE, sent|wparam, 1 },
2214     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2215     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2216
2217      /* in MDI frame */
2218     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2219     { WM_NCCALCSIZE, sent|wparam, 1 },
2220     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2221     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2222     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2223
2224     /* Win2k sends wparam set to
2225      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2226      * while Win9x doesn't bother to set child window id according to
2227      * CLIENTCREATESTRUCT.idFirstChild
2228      */
2229     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2230     { WM_SHOWWINDOW, sent|wparam, 1 },
2231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2232
2233     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2234
2235     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2236     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2237     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2238
2239     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2240     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2241
2242     /* Win9x: message sequence terminates here. */
2243
2244     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2245     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2246     { HCBT_SETFOCUS, hook }, /* in MDI client */
2247     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2248     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2249     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2250     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2251     { HCBT_SETFOCUS, hook|optional },
2252     { WM_KILLFOCUS, sent }, /* in MDI client */
2253     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2254     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2255     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2256     { WM_SETFOCUS, sent|defwinproc },
2257
2258     { WM_MDIACTIVATE, sent|defwinproc },
2259
2260      /* in MDI child */
2261     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2262     { WM_NCCALCSIZE, sent|wparam, 1 },
2263     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2264     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2265
2266      /* in MDI frame */
2267     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2268     { WM_NCCALCSIZE, sent|wparam, 1 },
2269     { 0x0093, sent|defwinproc|optional },
2270     { 0x0093, sent|defwinproc|optional },
2271     { 0x0093, sent|defwinproc|optional },
2272     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2273     { WM_MOVE, sent|defwinproc },
2274     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2275
2276      /* in MDI client */
2277     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2278     { WM_NCCALCSIZE, sent|wparam, 1 },
2279     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2280     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2281
2282      /* in MDI child */
2283     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2284     { WM_NCCALCSIZE, sent|wparam, 1 },
2285     { 0x0093, sent|optional },
2286     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2287     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2288
2289     { 0x0093, sent|optional },
2290     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2291     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2292     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2293     { 0x0093, sent|defwinproc|optional },
2294     { 0x0093, sent|defwinproc|optional },
2295     { 0x0093, sent|defwinproc|optional },
2296     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2297     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2298
2299     { 0 }
2300 };
2301 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2302 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2303     { HCBT_CREATEWND, hook },
2304     { WM_GETMINMAXINFO, sent },
2305     { WM_NCCREATE, sent }, 
2306     { WM_NCCALCSIZE, sent|wparam, 0 },
2307     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2308     { WM_CREATE, sent },
2309     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2310     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2311     { WM_MOVE, sent },
2312     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2313     { WM_GETMINMAXINFO, sent },
2314     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2315     { WM_GETMINMAXINFO, sent|defwinproc },
2316     { WM_NCCALCSIZE, sent|wparam, 1 },
2317     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2318     { WM_MOVE, sent|defwinproc },
2319     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2320      /* in MDI frame */
2321     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2322     { WM_NCCALCSIZE, sent|wparam, 1 },
2323     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2324     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2325     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2326     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2327     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2328     /* Win2k sends wparam set to
2329      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2330      * while Win9x doesn't bother to set child window id according to
2331      * CLIENTCREATESTRUCT.idFirstChild
2332      */
2333     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2334     { 0 }
2335 };
2336 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2337 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2338     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2339     { HCBT_SYSCOMMAND, hook },
2340     { WM_CLOSE, sent|defwinproc },
2341     { WM_MDIDESTROY, sent }, /* in MDI client */
2342
2343     /* bring the 1st MDI child to top */
2344     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2345     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2346
2347     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2348
2349     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2350     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2351     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2352
2353     /* maximize the 1st MDI child */
2354     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2355     { WM_GETMINMAXINFO, sent|defwinproc },
2356     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2357     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2358     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2359     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2360     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2361
2362     /* restore the 2nd MDI child */
2363     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2364     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2365     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2366     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2367
2368     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2369
2370     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2371     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2372
2373     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2374
2375     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2376      /* in MDI frame */
2377     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2378     { WM_NCCALCSIZE, sent|wparam, 1 },
2379     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2380     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2381     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2382
2383     /* bring the 1st MDI child to top */
2384     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2385     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2386     { HCBT_SETFOCUS, hook },
2387     { WM_KILLFOCUS, sent|defwinproc },
2388     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2389     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2390     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2391     { WM_SETFOCUS, sent }, /* in MDI client */
2392     { HCBT_SETFOCUS, hook },
2393     { WM_KILLFOCUS, sent }, /* in MDI client */
2394     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2395     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2396     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2397     { WM_SETFOCUS, sent|defwinproc },
2398     { WM_MDIACTIVATE, sent|defwinproc },
2399     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2400
2401     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2402     { WM_SHOWWINDOW, sent|wparam, 1 },
2403     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2404     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2405     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2406     { WM_MDIREFRESHMENU, sent },
2407
2408     { HCBT_DESTROYWND, hook },
2409     /* Win2k sends wparam set to
2410      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2411      * while Win9x doesn't bother to set child window id according to
2412      * CLIENTCREATESTRUCT.idFirstChild
2413      */
2414     { 0x0090, sent|defwinproc|optional },
2415     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2416     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2417     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2418     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2419     { WM_ERASEBKGND, sent|parent|optional },
2420     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2421
2422     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2423     { WM_DESTROY, sent|defwinproc },
2424     { WM_NCDESTROY, sent|defwinproc },
2425     { 0 }
2426 };
2427 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2428 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2429     { WM_MDIDESTROY, sent }, /* in MDI client */
2430     { WM_SHOWWINDOW, sent|wparam, 0 },
2431     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2432     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2433     { WM_ERASEBKGND, sent|parent|optional },
2434     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2435
2436     { HCBT_SETFOCUS, hook },
2437     { WM_KILLFOCUS, sent },
2438     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2439     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2440     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2441     { WM_SETFOCUS, sent }, /* in MDI client */
2442     { HCBT_SETFOCUS, hook },
2443     { WM_KILLFOCUS, sent }, /* in MDI client */
2444     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2445     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2446     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2447     { WM_SETFOCUS, sent },
2448
2449      /* in MDI child */
2450     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2451     { WM_NCCALCSIZE, sent|wparam, 1 },
2452     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2453     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2454
2455      /* in MDI frame */
2456     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2457     { WM_NCCALCSIZE, sent|wparam, 1 },
2458     { 0x0093, sent|defwinproc|optional },
2459     { 0x0093, sent|defwinproc|optional },
2460     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2461     { WM_MOVE, sent|defwinproc },
2462     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2463
2464      /* in MDI client */
2465     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2466     { WM_NCCALCSIZE, sent|wparam, 1 },
2467     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2468     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2469
2470      /* in MDI child */
2471     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2472     { WM_NCCALCSIZE, sent|wparam, 1 },
2473     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2474     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2475
2476      /* in MDI child */
2477     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2478     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2479     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2480     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2481
2482      /* in MDI frame */
2483     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2484     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2485     { 0x0093, sent|defwinproc|optional },
2486     { 0x0093, sent|defwinproc|optional },
2487     { 0x0093, sent|defwinproc|optional },
2488     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2489     { WM_MOVE, sent|defwinproc },
2490     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2491
2492      /* in MDI client */
2493     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2494     { WM_NCCALCSIZE, sent|wparam, 1 },
2495     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2496     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2497
2498      /* in MDI child */
2499     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2500     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2501     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2502     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2503     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2504     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2505
2506     { 0x0093, sent|defwinproc|optional },
2507     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2508     { 0x0093, sent|defwinproc|optional },
2509     { 0x0093, sent|defwinproc|optional },
2510     { 0x0093, sent|defwinproc|optional },
2511     { 0x0093, sent|optional },
2512
2513     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2514     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2515     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2516     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2517     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2518
2519      /* in MDI frame */
2520     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2521     { WM_NCCALCSIZE, sent|wparam, 1 },
2522     { 0x0093, sent|defwinproc|optional },
2523     { 0x0093, sent|defwinproc|optional },
2524     { 0x0093, sent|defwinproc|optional },
2525     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2526     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2527     { 0x0093, sent|optional },
2528
2529     { WM_NCACTIVATE, sent|wparam, 0 },
2530     { WM_MDIACTIVATE, sent },
2531
2532     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2533     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2534     { WM_NCCALCSIZE, sent|wparam, 1 },
2535
2536     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2537
2538     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2539     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2540     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2541
2542      /* in MDI child */
2543     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2544     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2545     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2546     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2547
2548      /* in MDI frame */
2549     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2550     { WM_NCCALCSIZE, sent|wparam, 1 },
2551     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2552     { WM_MOVE, sent|defwinproc },
2553     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2554
2555      /* in MDI client */
2556     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2557     { WM_NCCALCSIZE, sent|wparam, 1 },
2558     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2559     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2560     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2561     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2562     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2563     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2564     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2565
2566     { HCBT_SETFOCUS, hook },
2567     { WM_KILLFOCUS, sent },
2568     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2569     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2570     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2571     { WM_SETFOCUS, sent }, /* in MDI client */
2572
2573     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2574
2575     { HCBT_DESTROYWND, hook },
2576     /* Win2k sends wparam set to
2577      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2578      * while Win9x doesn't bother to set child window id according to
2579      * CLIENTCREATESTRUCT.idFirstChild
2580      */
2581     { 0x0090, sent|optional },
2582     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2583
2584     { WM_SHOWWINDOW, sent|wparam, 0 },
2585     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2586     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2587     { WM_ERASEBKGND, sent|parent|optional },
2588     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2589
2590     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2591     { WM_DESTROY, sent },
2592     { WM_NCDESTROY, sent },
2593     { 0 }
2594 };
2595 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2596 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2597     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2598     { WM_GETMINMAXINFO, sent },
2599     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2600     { WM_NCCALCSIZE, sent|wparam, 1 },
2601     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2602     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2603
2604     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2605     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2606     { HCBT_SETFOCUS, hook },
2607     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2608     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2609     { WM_SETFOCUS, sent }, /* in MDI client */
2610     { HCBT_SETFOCUS, hook },
2611     { WM_KILLFOCUS, sent }, /* in MDI client */
2612     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2613     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2614     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2615     { WM_SETFOCUS, sent|defwinproc },
2616     { WM_MDIACTIVATE, sent|defwinproc },
2617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2618     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2619      /* in MDI frame */
2620     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2621     { WM_NCCALCSIZE, sent|wparam, 1 },
2622     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2623     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2624     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2625     { 0 }
2626 };
2627 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2628 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2629     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2630     { WM_GETMINMAXINFO, sent },
2631     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2632     { WM_GETMINMAXINFO, sent|defwinproc },
2633     { WM_NCCALCSIZE, sent|wparam, 1 },
2634     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2635     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2636
2637     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2638     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2639     { HCBT_SETFOCUS, hook },
2640     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2641     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2642     { WM_SETFOCUS, sent }, /* in MDI client */
2643     { HCBT_SETFOCUS, hook },
2644     { WM_KILLFOCUS, sent }, /* in MDI client */
2645     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2646     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2647     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2648     { WM_SETFOCUS, sent|defwinproc },
2649     { WM_MDIACTIVATE, sent|defwinproc },
2650     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2651     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2652     { 0 }
2653 };
2654 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2655 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2656     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2657     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2658     { WM_GETMINMAXINFO, sent },
2659     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2660     { WM_GETMINMAXINFO, sent|defwinproc },
2661     { WM_NCCALCSIZE, sent|wparam, 1 },
2662     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2663     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2664     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
2665     { WM_MOVE, sent|defwinproc },
2666     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2667
2668     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2669     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2670     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2671     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2672     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2673     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2674      /* in MDI frame */
2675     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2676     { WM_NCCALCSIZE, sent|wparam, 1 },
2677     { 0x0093, sent|defwinproc|optional },
2678     { 0x0094, sent|defwinproc|optional },
2679     { 0x0094, sent|defwinproc|optional },
2680     { 0x0094, sent|defwinproc|optional },
2681     { 0x0094, sent|defwinproc|optional },
2682     { 0x0093, sent|defwinproc|optional },
2683     { 0x0093, sent|defwinproc|optional },
2684     { 0x0091, sent|defwinproc|optional },
2685     { 0x0092, sent|defwinproc|optional },
2686     { 0x0092, sent|defwinproc|optional },
2687     { 0x0092, sent|defwinproc|optional },
2688     { 0x0092, sent|defwinproc|optional },
2689     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2690     { WM_MOVE, sent|defwinproc },
2691     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2692     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2693      /* in MDI client */
2694     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2695     { WM_NCCALCSIZE, sent|wparam, 1 },
2696     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2697     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2698      /* in MDI child */
2699     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2700     { WM_GETMINMAXINFO, sent|defwinproc },
2701     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2702     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2703     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2704     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2705     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2706     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2707     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2708     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2709      /* in MDI frame */
2710     { 0x0093, sent|optional },
2711     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2712     { 0x0093, sent|defwinproc|optional },
2713     { 0x0093, sent|defwinproc|optional },
2714     { 0x0093, sent|defwinproc|optional },
2715     { 0x0091, sent|defwinproc|optional },
2716     { 0x0092, sent|defwinproc|optional },
2717     { 0x0092, sent|defwinproc|optional },
2718     { 0x0092, sent|defwinproc|optional },
2719     { 0x0092, sent|defwinproc|optional },
2720     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2722     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2723     { 0 }
2724 };
2725 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2726 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2727     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2728     { WM_GETMINMAXINFO, sent },
2729     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2730     { WM_NCCALCSIZE, sent|wparam, 1 },
2731     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2732     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2733     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2734      /* in MDI frame */
2735     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2736     { WM_NCCALCSIZE, sent|wparam, 1 },
2737     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2738     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2739     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2740     { 0 }
2741 };
2742 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2743 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2744     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2745     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2746     { WM_NCCALCSIZE, sent|wparam, 1 },
2747     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2748     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2749     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2750      /* in MDI frame */
2751     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2752     { WM_NCCALCSIZE, sent|wparam, 1 },
2753     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2754     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2755     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2756     { 0 }
2757 };
2758 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2759 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2760     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2761     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2762     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
2763     { WM_NCCALCSIZE, sent|wparam, 1 },
2764     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2765     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2766     { WM_MOVE, sent|defwinproc },
2767     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2768     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2769     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2770     { HCBT_SETFOCUS, hook },
2771     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2772     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2773     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2774     { WM_SETFOCUS, sent },
2775     { 0 }
2776 };
2777 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2778 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2779     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2780     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
2781     { WM_NCCALCSIZE, sent|wparam, 1 },
2782     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2783     { WM_MOVE, sent|defwinproc },
2784     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2785     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2786     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2787     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2788     /* FIXME: Wine creates an icon/title window while Windows doesn't */
2789     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2790     { 0 }
2791 };
2792 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2793 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2794     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2795     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
2796     { WM_NCCALCSIZE, sent|wparam, 1 },
2797     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2798     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2799     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2800     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2801      /* in MDI frame */
2802     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2803     { WM_NCCALCSIZE, sent|wparam, 1 },
2804     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2805     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2806     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2807     { 0 }
2808 };
2809
2810 static HWND mdi_client;
2811 static WNDPROC old_mdi_client_proc;
2812
2813 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2814 {
2815     struct message msg;
2816
2817     /* do not log painting messages */
2818     if (message != WM_PAINT &&
2819         message != WM_NCPAINT &&
2820         message != WM_SYNCPAINT &&
2821         message != WM_ERASEBKGND &&
2822         message != WM_NCHITTEST &&
2823         message != WM_GETTEXT &&
2824         message != WM_MDIGETACTIVE &&
2825         message != WM_GETICON &&
2826         message != WM_DEVICECHANGE)
2827     {
2828         trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2829
2830         switch (message)
2831         {
2832             case WM_WINDOWPOSCHANGING:
2833             case WM_WINDOWPOSCHANGED:
2834             {
2835                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2836
2837                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2838                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2839                       winpos->hwnd, winpos->hwndInsertAfter,
2840                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2841                 dump_winpos_flags(winpos->flags);
2842
2843                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2844                  * in the high word for internal purposes
2845                  */
2846                 wParam = winpos->flags & 0xffff;
2847                 /* We are not interested in the flags that don't match under XP and Win9x */
2848                 wParam &= ~(SWP_NOZORDER);
2849                 break;
2850             }
2851         }
2852
2853         msg.message = message;
2854         msg.flags = sent|wparam|lparam;
2855         msg.wParam = wParam;
2856         msg.lParam = lParam;
2857         add_message(&msg);
2858     }
2859
2860     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2861 }
2862
2863 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2864 {
2865     static long defwndproc_counter = 0;
2866     LRESULT ret;
2867     struct message msg;
2868
2869     /* do not log painting messages */
2870     if (message != WM_PAINT &&
2871         message != WM_NCPAINT &&
2872         message != WM_SYNCPAINT &&
2873         message != WM_ERASEBKGND &&
2874         message != WM_NCHITTEST &&
2875         message != WM_GETTEXT &&
2876         message != WM_GETICON &&
2877         message != WM_DEVICECHANGE)
2878     {
2879         trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2880
2881         switch (message)
2882         {
2883             case WM_WINDOWPOSCHANGING:
2884             case WM_WINDOWPOSCHANGED:
2885             {
2886                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2887
2888                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2889                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2890                       winpos->hwnd, winpos->hwndInsertAfter,
2891                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2892                 dump_winpos_flags(winpos->flags);
2893
2894                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2895                  * in the high word for internal purposes
2896                  */
2897                 wParam = winpos->flags & 0xffff;
2898                 /* We are not interested in the flags that don't match under XP and Win9x */
2899                 wParam &= ~(SWP_NOZORDER);
2900                 break;
2901             }
2902
2903             case WM_MDIACTIVATE:
2904             {
2905                 HWND active, client = GetParent(hwnd);
2906
2907                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2908
2909                 if (hwnd == (HWND)lParam) /* if we are being activated */
2910                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2911                 else
2912                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2913                 break;
2914             }
2915         }
2916
2917         msg.message = message;
2918         msg.flags = sent|wparam|lparam;
2919         if (defwndproc_counter) msg.flags |= defwinproc;
2920         msg.wParam = wParam;
2921         msg.lParam = lParam;
2922         add_message(&msg);
2923     }
2924
2925     defwndproc_counter++;
2926     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2927     defwndproc_counter--;
2928
2929     return ret;
2930 }
2931
2932 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2933 {
2934     static long defwndproc_counter = 0;
2935     LRESULT ret;
2936     struct message msg;
2937
2938     /* do not log painting messages */
2939     if (message != WM_PAINT &&
2940         message != WM_NCPAINT &&
2941         message != WM_SYNCPAINT &&
2942         message != WM_ERASEBKGND &&
2943         message != WM_NCHITTEST &&
2944         message != WM_GETTEXT &&
2945         message != WM_GETICON &&
2946         message != WM_DEVICECHANGE)
2947     {
2948         trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2949
2950         switch (message)
2951         {
2952             case WM_WINDOWPOSCHANGING:
2953             case WM_WINDOWPOSCHANGED:
2954             {
2955                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2956
2957                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2958                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2959                       winpos->hwnd, winpos->hwndInsertAfter,
2960                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2961                 dump_winpos_flags(winpos->flags);
2962
2963                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2964                  * in the high word for internal purposes
2965                  */
2966                 wParam = winpos->flags & 0xffff;
2967                 /* We are not interested in the flags that don't match under XP and Win9x */
2968                 wParam &= ~(SWP_NOZORDER);
2969                 break;
2970             }
2971         }
2972
2973         msg.message = message;
2974         msg.flags = sent|wparam|lparam;
2975         if (defwndproc_counter) msg.flags |= defwinproc;
2976         msg.wParam = wParam;
2977         msg.lParam = lParam;
2978         add_message(&msg);
2979     }
2980
2981     defwndproc_counter++;
2982     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2983     defwndproc_counter--;
2984
2985     return ret;
2986 }
2987
2988 static BOOL mdi_RegisterWindowClasses(void)
2989 {
2990     WNDCLASSA cls;
2991
2992     cls.style = 0;
2993     cls.lpfnWndProc = mdi_frame_wnd_proc;
2994     cls.cbClsExtra = 0;
2995     cls.cbWndExtra = 0;
2996     cls.hInstance = GetModuleHandleA(0);
2997     cls.hIcon = 0;
2998     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2999     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3000     cls.lpszMenuName = NULL;
3001     cls.lpszClassName = "MDI_frame_class";
3002     if (!RegisterClassA(&cls)) return FALSE;
3003
3004     cls.lpfnWndProc = mdi_child_wnd_proc;
3005     cls.lpszClassName = "MDI_child_class";
3006     if (!RegisterClassA(&cls)) return FALSE;
3007
3008     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3009     old_mdi_client_proc = cls.lpfnWndProc;
3010     cls.hInstance = GetModuleHandleA(0);
3011     cls.lpfnWndProc = mdi_client_hook_proc;
3012     cls.lpszClassName = "MDI_client_class";
3013     if (!RegisterClassA(&cls)) assert(0);
3014
3015     return TRUE;
3016 }
3017
3018 static void test_mdi_messages(void)
3019 {
3020     MDICREATESTRUCTA mdi_cs;
3021     CLIENTCREATESTRUCT client_cs;
3022     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3023     BOOL zoomed;
3024     HMENU hMenu = CreateMenu();
3025
3026     assert(mdi_RegisterWindowClasses());
3027
3028     flush_sequence();
3029
3030     trace("creating MDI frame window\n");
3031     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3032                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3033                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3034                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3035                                 GetDesktopWindow(), hMenu,
3036                                 GetModuleHandleA(0), NULL);
3037     assert(mdi_frame);
3038     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3039
3040     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3041     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3042
3043     trace("creating MDI client window\n");
3044     client_cs.hWindowMenu = 0;
3045     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3046     mdi_client = CreateWindowExA(0, "MDI_client_class",
3047                                  NULL,
3048                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3049                                  0, 0, 0, 0,
3050                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3051     assert(mdi_client);
3052     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3053
3054     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3055     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3056
3057     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3058     ok(!active_child, "wrong active MDI child %p\n", active_child);
3059     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3060
3061     SetFocus(0);
3062     flush_sequence();
3063
3064     trace("creating invisible MDI child window\n");
3065     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3066                                 WS_CHILD,
3067                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3068                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3069     assert(mdi_child);
3070
3071     flush_sequence();
3072     ShowWindow(mdi_child, SW_SHOWNORMAL);
3073     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3074
3075     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3076     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3077
3078     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3079     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3080
3081     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3082     ok(!active_child, "wrong active MDI child %p\n", active_child);
3083     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3084
3085     ShowWindow(mdi_child, SW_HIDE);
3086     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3087     flush_sequence();
3088
3089     ShowWindow(mdi_child, SW_SHOW);
3090     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3091
3092     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3093     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3094
3095     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3096     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3097
3098     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3099     ok(!active_child, "wrong active MDI child %p\n", active_child);
3100     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3101
3102     DestroyWindow(mdi_child);
3103     flush_sequence();
3104
3105     trace("creating visible MDI child window\n");
3106     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3107                                 WS_CHILD | WS_VISIBLE,
3108                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3109                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3110     assert(mdi_child);
3111     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3112
3113     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3114     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3115
3116     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3117     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3118
3119     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3120     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3121     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3122     flush_sequence();
3123
3124     DestroyWindow(mdi_child);
3125     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3126
3127     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3128     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3129
3130     /* Win2k: MDI client still returns a just destroyed child as active
3131      * Win9x: MDI client returns 0
3132      */
3133     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3134     ok(active_child == mdi_child || /* win2k */
3135        !active_child, /* win9x */
3136        "wrong active MDI child %p\n", active_child);
3137     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3138
3139     flush_sequence();
3140
3141     trace("creating invisible MDI child window\n");
3142     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3143                                 WS_CHILD,
3144                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3145                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3146     assert(mdi_child2);
3147     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3148
3149     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3150     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3151
3152     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3153     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3154
3155     /* Win2k: MDI client still returns a just destroyed child as active
3156      * Win9x: MDI client returns mdi_child2
3157      */
3158     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3159     ok(active_child == mdi_child || /* win2k */
3160        active_child == mdi_child2, /* win9x */
3161        "wrong active MDI child %p\n", active_child);
3162     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3163     flush_sequence();
3164
3165     ShowWindow(mdi_child2, SW_MAXIMIZE);
3166     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3167
3168     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3169     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3170
3171     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3172     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3173     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3174     flush_sequence();
3175
3176     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3177     ok(GetFocus() == mdi_child2 || /* win2k */
3178        GetFocus() == 0, /* win9x */
3179        "wrong focus window %p\n", GetFocus());
3180
3181     SetFocus(0);
3182     flush_sequence();
3183
3184     ShowWindow(mdi_child2, SW_HIDE);
3185     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3186
3187     ShowWindow(mdi_child2, SW_RESTORE);
3188     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3189     flush_sequence();
3190
3191     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3192     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3193
3194     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3195     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3196     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3197     flush_sequence();
3198
3199     SetFocus(0);
3200     flush_sequence();
3201
3202     ShowWindow(mdi_child2, SW_HIDE);
3203     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3204
3205     ShowWindow(mdi_child2, SW_SHOW);
3206     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3207
3208     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3209     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3210
3211     ShowWindow(mdi_child2, SW_MAXIMIZE);
3212     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3213
3214     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3215     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3216
3217     ShowWindow(mdi_child2, SW_RESTORE);
3218     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3219
3220     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3221     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3222
3223     ShowWindow(mdi_child2, SW_MINIMIZE);
3224     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3225
3226     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3227     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3228
3229     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3230     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3231     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3232     flush_sequence();
3233
3234     ShowWindow(mdi_child2, SW_RESTORE);
3235     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3236
3237     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3238     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3239
3240     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3241     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3242     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3243     flush_sequence();
3244
3245     SetFocus(0);
3246     flush_sequence();
3247
3248     ShowWindow(mdi_child2, SW_HIDE);
3249     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3250
3251     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3252     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3253
3254     DestroyWindow(mdi_child2);
3255     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3256
3257     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3258     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3259
3260     /* test for maximized MDI children */
3261     trace("creating maximized visible MDI child window 1\n");
3262     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3263                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3264                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3265                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3266     assert(mdi_child);
3267     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3268     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3269
3270     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3271     ok(GetFocus() == mdi_child || /* win2k */
3272        GetFocus() == 0, /* win9x */
3273        "wrong focus window %p\n", GetFocus());
3274
3275     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3276     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3277     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3278     flush_sequence();
3279
3280     trace("creating maximized visible MDI child window 2\n");
3281     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3282                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3283                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3284                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3285     assert(mdi_child2);
3286     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3287     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3288     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3289
3290     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3291     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3292
3293     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3294     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3295     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3296     flush_sequence();
3297
3298     trace("destroying maximized visible MDI child window 2\n");
3299     DestroyWindow(mdi_child2);
3300     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3301
3302     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3303
3304     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3305     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3306
3307     /* Win2k: MDI client still returns a just destroyed child as active
3308      * Win9x: MDI client returns 0
3309      */
3310     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3311     ok(active_child == mdi_child2 || /* win2k */
3312        !active_child, /* win9x */
3313        "wrong active MDI child %p\n", active_child);
3314     flush_sequence();
3315
3316     ShowWindow(mdi_child, SW_MAXIMIZE);
3317     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3318     flush_sequence();
3319
3320     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3321     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3322
3323     trace("re-creating maximized visible MDI child window 2\n");
3324     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3325                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3326                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3327                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3328     assert(mdi_child2);
3329     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3330     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3331     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3332
3333     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3334     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3335
3336     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3337     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3338     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3339     flush_sequence();
3340
3341     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3342     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3343     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3344
3345     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3346     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3347     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3348
3349     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3350     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3351     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3352     flush_sequence();
3353
3354     DestroyWindow(mdi_child);
3355     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3356
3357     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3358     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3359
3360     /* Win2k: MDI client still returns a just destroyed child as active
3361      * Win9x: MDI client returns 0
3362      */
3363     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3364     ok(active_child == mdi_child || /* win2k */
3365        !active_child, /* win9x */
3366        "wrong active MDI child %p\n", active_child);
3367     flush_sequence();
3368
3369     trace("creating maximized invisible MDI child window\n");
3370     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3371                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3372                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3373                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3374     assert(mdi_child2);
3375     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
3376     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3377     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3378     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3379
3380     /* Win2k: MDI client still returns a just destroyed child as active
3381      * Win9x: MDI client returns 0
3382      */
3383     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3384     ok(active_child == mdi_child || /* win2k */
3385        !active_child, /* win9x */
3386        "wrong active MDI child %p\n", active_child);
3387     flush_sequence();
3388
3389     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3390     ShowWindow(mdi_child2, SW_MAXIMIZE);
3391     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3392     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3393     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3394     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3395
3396     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3397     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3398     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3399     flush_sequence();
3400
3401     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3402     flush_sequence();
3403
3404     /* end of test for maximized MDI children */
3405     SetFocus(0);
3406     flush_sequence();
3407     trace("creating maximized visible MDI child window 1(Switch test)\n");
3408     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3409                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3410                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3411                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3412     assert(mdi_child);
3413     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3414     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3415
3416     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3417     ok(GetFocus() == mdi_child || /* win2k */
3418        GetFocus() == 0, /* win9x */
3419        "wrong focus window %p(Switch test)\n", GetFocus());
3420
3421     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3422     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3423     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3424     flush_sequence();
3425
3426     trace("creating maximized visible MDI child window 2(Switch test)\n");
3427     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3428                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3429                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3430                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3431     assert(mdi_child2);
3432     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3433
3434     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3435     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3436
3437     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3438     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3439
3440     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3441     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3442     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3443     flush_sequence();
3444
3445     trace("Switch child window.\n");
3446     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3447     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3448     trace("end of test for switch maximized MDI children\n");
3449     flush_sequence();
3450
3451     /* Prepare for switching test of not maximized MDI children  */
3452     ShowWindow( mdi_child, SW_NORMAL );
3453     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3454     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3455     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3456     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3457     flush_sequence();
3458
3459     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3460     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3461     trace("end of test for switch not maximized MDI children\n");
3462     flush_sequence();
3463
3464     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3465     flush_sequence();
3466
3467     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3468     flush_sequence();
3469
3470     SetFocus(0);
3471     flush_sequence();
3472     /* end of tests for switch maximized/not maximized MDI children */
3473
3474     mdi_cs.szClass = "MDI_child_Class";
3475     mdi_cs.szTitle = "MDI child";
3476     mdi_cs.hOwner = GetModuleHandleA(0);
3477     mdi_cs.x = 0;
3478     mdi_cs.y = 0;
3479     mdi_cs.cx = CW_USEDEFAULT;
3480     mdi_cs.cy = CW_USEDEFAULT;
3481     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3482     mdi_cs.lParam = 0;
3483     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3484     ok(mdi_child != 0, "MDI child creation failed\n");
3485     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3486
3487     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3488
3489     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3490     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3491
3492     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3493     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3494     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3495
3496     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3497     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3498     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3499     flush_sequence();
3500
3501     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3502     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3503
3504     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3505     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3506     ok(!active_child, "wrong active MDI child %p\n", active_child);
3507
3508     SetFocus(0);
3509     flush_sequence();
3510
3511     DestroyWindow(mdi_client);
3512     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3513
3514     /* test maximization of MDI child with invisible parent */
3515     client_cs.hWindowMenu = 0;
3516     mdi_client = CreateWindow("MDI_client_class",
3517                                  NULL,
3518                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3519                                  0, 0, 660, 430,
3520                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3521     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3522
3523     ShowWindow(mdi_client, SW_HIDE);
3524     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3525
3526     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3527                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3528                                 0, 0, 650, 440,
3529                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3530     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3531
3532     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3533     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3534     zoomed = IsZoomed(mdi_child);
3535     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3536     
3537     ShowWindow(mdi_client, SW_SHOW);
3538     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3539
3540     DestroyWindow(mdi_child);
3541     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3542
3543     /* end of test for maximization of MDI child with invisible parent */
3544
3545     DestroyWindow(mdi_client);
3546     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3547
3548     DestroyWindow(mdi_frame);
3549     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3550 }
3551 /************************* End of MDI test **********************************/
3552
3553 static void test_WM_SETREDRAW(HWND hwnd)
3554 {
3555     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3556
3557     flush_sequence();
3558
3559     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3560     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3561
3562     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3563     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3564
3565     flush_sequence();
3566     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3567     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3568
3569     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3570     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3571
3572     /* restore original WS_VISIBLE state */
3573     SetWindowLongA(hwnd, GWL_STYLE, style);
3574
3575     flush_sequence();
3576 }
3577
3578 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3579 {
3580     struct message msg;
3581
3582     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3583
3584     /* explicitly ignore WM_GETICON message */
3585     if (message == WM_GETICON) return 0;
3586
3587     switch (message)
3588     {
3589         /* ignore */
3590         case WM_MOUSEMOVE:
3591         case WM_SETCURSOR:
3592         case WM_DEVICECHANGE:
3593             return 0;
3594         case WM_NCHITTEST:
3595             return HTCLIENT;
3596
3597         case WM_WINDOWPOSCHANGING:
3598         case WM_WINDOWPOSCHANGED:
3599         {
3600             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3601
3602             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3603             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
3604                   winpos->hwnd, winpos->hwndInsertAfter,
3605                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3606             dump_winpos_flags(winpos->flags);
3607
3608             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3609              * in the high word for internal purposes
3610              */
3611             wParam = winpos->flags & 0xffff;
3612             /* We are not interested in the flags that don't match under XP and Win9x */
3613             wParam &= ~(SWP_NOZORDER);
3614             break;
3615         }
3616     }
3617
3618     msg.message = message;
3619     msg.flags = sent|wparam|lparam;
3620     msg.wParam = wParam;
3621     msg.lParam = lParam;
3622     add_message(&msg);
3623
3624     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3625     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3626     return 0;
3627 }
3628
3629 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3630 {
3631     DWORD style, exstyle;
3632     INT xmin, xmax;
3633     BOOL ret;
3634
3635     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3636     style = GetWindowLongA(hwnd, GWL_STYLE);
3637     /* do not be confused by WS_DLGFRAME set */
3638     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3639
3640     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3641     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3642
3643     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3644     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3645     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3646         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3647     else
3648         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3649
3650     style = GetWindowLongA(hwnd, GWL_STYLE);
3651     if (set) ok(style & set, "style %08x should be set\n", set);
3652     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3653
3654     /* a subsequent call should do nothing */
3655     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3656     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3657     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3658
3659     xmin = 0xdeadbeef;
3660     xmax = 0xdeadbeef;
3661     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3662     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3663     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3664     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3665     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3666     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3667 }
3668
3669 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3670 {
3671     DWORD style, exstyle;
3672     SCROLLINFO si;
3673     BOOL ret;
3674
3675     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3676     style = GetWindowLongA(hwnd, GWL_STYLE);
3677     /* do not be confused by WS_DLGFRAME set */
3678     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3679
3680     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3681     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3682
3683     si.cbSize = sizeof(si);
3684     si.fMask = SIF_RANGE;
3685     si.nMin = min;
3686     si.nMax = max;
3687     SetScrollInfo(hwnd, ctl, &si, TRUE);
3688     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3689         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3690     else
3691         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3692
3693     style = GetWindowLongA(hwnd, GWL_STYLE);
3694     if (set) ok(style & set, "style %08x should be set\n", set);
3695     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3696
3697     /* a subsequent call should do nothing */
3698     SetScrollInfo(hwnd, ctl, &si, TRUE);
3699     if (style & WS_HSCROLL)
3700         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3701     else if (style & WS_VSCROLL)
3702         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3703     else
3704         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3705
3706     si.fMask = SIF_PAGE;
3707     si.nPage = 5;
3708     SetScrollInfo(hwnd, ctl, &si, FALSE);
3709     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3710
3711     si.fMask = SIF_POS;
3712     si.nPos = max - 1;
3713     SetScrollInfo(hwnd, ctl, &si, FALSE);
3714     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3715
3716     si.fMask = SIF_RANGE;
3717     si.nMin = 0xdeadbeef;
3718     si.nMax = 0xdeadbeef;
3719     ret = GetScrollInfo(hwnd, ctl, &si);
3720     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3721     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3722     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3723     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3724 }
3725
3726 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3727 static void test_scroll_messages(HWND hwnd)
3728 {
3729     SCROLLINFO si;
3730     INT min, max;
3731     BOOL ret;
3732
3733     min = 0xdeadbeef;
3734     max = 0xdeadbeef;
3735     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3736     ok( ret, "GetScrollRange error %d\n", GetLastError());
3737     if (sequence->message != WmGetScrollRangeSeq[0].message)
3738         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3739     /* values of min and max are undefined */
3740     flush_sequence();
3741
3742     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3743     ok( ret, "SetScrollRange error %d\n", GetLastError());
3744     if (sequence->message != WmSetScrollRangeSeq[0].message)
3745         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3746     flush_sequence();
3747
3748     min = 0xdeadbeef;
3749     max = 0xdeadbeef;
3750     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3751     ok( ret, "GetScrollRange error %d\n", GetLastError());
3752     if (sequence->message != WmGetScrollRangeSeq[0].message)
3753         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3754     /* values of min and max are undefined */
3755     flush_sequence();
3756
3757     si.cbSize = sizeof(si);
3758     si.fMask = SIF_RANGE;
3759     si.nMin = 20;
3760     si.nMax = 160;
3761     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3762     if (sequence->message != WmSetScrollRangeSeq[0].message)
3763         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3764     flush_sequence();
3765
3766     si.fMask = SIF_PAGE;
3767     si.nPage = 10;
3768     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3769     if (sequence->message != WmSetScrollRangeSeq[0].message)
3770         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3771     flush_sequence();
3772
3773     si.fMask = SIF_POS;
3774     si.nPos = 20;
3775     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3776     if (sequence->message != WmSetScrollRangeSeq[0].message)
3777         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3778     flush_sequence();
3779
3780     si.fMask = SIF_RANGE;
3781     si.nMin = 0xdeadbeef;
3782     si.nMax = 0xdeadbeef;
3783     ret = GetScrollInfo(hwnd, SB_CTL, &si);
3784     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3785     if (sequence->message != WmGetScrollInfoSeq[0].message)
3786         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3787     /* values of min and max are undefined */
3788     flush_sequence();
3789
3790     /* set WS_HSCROLL */
3791     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3792     /* clear WS_HSCROLL */
3793     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3794
3795     /* set WS_HSCROLL */
3796     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3797     /* clear WS_HSCROLL */
3798     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3799
3800     /* set WS_VSCROLL */
3801     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3802     /* clear WS_VSCROLL */
3803     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3804
3805     /* set WS_VSCROLL */
3806     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3807     /* clear WS_VSCROLL */
3808     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3809 }
3810
3811 static void test_showwindow(void)
3812 {
3813     HWND hwnd, hchild;
3814     RECT rc;
3815
3816     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3817                            100, 100, 200, 200, 0, 0, 0, NULL);
3818     ok (hwnd != 0, "Failed to create overlapped window\n");
3819     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3820                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3821     ok (hchild != 0, "Failed to create child\n");
3822     flush_sequence();
3823
3824     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3825     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3826     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3827     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3828     trace("done\n");
3829
3830     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3831     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3832     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3833     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3834     trace("done\n");
3835     /* back to invisible */
3836     ShowWindow(hchild, SW_HIDE);
3837     ShowWindow(hwnd, SW_HIDE);
3838     flush_sequence();
3839     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3840     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3841     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3842     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3843     trace("done\n");
3844     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3845     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3846     flush_sequence();
3847     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3848     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3849     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3850     trace("done\n");
3851     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3852     ShowWindow( hwnd, SW_SHOW);
3853     flush_sequence();
3854     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3855     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3856     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3857     trace("done\n");
3858
3859     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3860     ShowWindow( hchild, SW_HIDE);
3861     flush_sequence();
3862     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3863     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3864     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3865     trace("done\n");
3866
3867     SetCapture(hchild);
3868     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3869     DestroyWindow(hchild);
3870     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3871
3872     DestroyWindow(hwnd);
3873     flush_sequence();
3874
3875     /* Popup windows */
3876     /* Test 1:
3877      * 1. Create invisible maximized popup window.
3878      * 2. Move and resize it.
3879      * 3. Show it maximized.
3880      */
3881     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3882     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3883                            100, 100, 200, 200, 0, 0, 0, NULL);
3884     ok (hwnd != 0, "Failed to create popup window\n");
3885     ok(IsZoomed(hwnd), "window should be maximized\n");
3886     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3887     trace("done\n");
3888
3889     GetWindowRect(hwnd, &rc);
3890     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3891         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3892         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3893         rc.left, rc.top, rc.right, rc.bottom);
3894     /* Reset window's size & position */
3895     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3896     ok(IsZoomed(hwnd), "window should be maximized\n");
3897     flush_sequence();
3898
3899     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3900     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3901     ok(IsZoomed(hwnd), "window should be maximized\n");
3902     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3903     trace("done\n");
3904
3905     GetWindowRect(hwnd, &rc);
3906     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3907         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3908         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3909         rc.left, rc.top, rc.right, rc.bottom);
3910     DestroyWindow(hwnd);
3911     flush_sequence();
3912
3913     /* Test 2:
3914      * 1. Create invisible maximized popup window.
3915      * 2. Show it maximized.
3916      */
3917     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3918     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3919                            100, 100, 200, 200, 0, 0, 0, NULL);
3920     ok (hwnd != 0, "Failed to create popup window\n");
3921     ok(IsZoomed(hwnd), "window should be maximized\n");
3922     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3923     trace("done\n");
3924
3925     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3926     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3927     ok(IsZoomed(hwnd), "window should be maximized\n");
3928     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3929     trace("done\n");
3930     DestroyWindow(hwnd);
3931     flush_sequence();
3932
3933     /* Test 3:
3934      * 1. Create visible maximized popup window.
3935      */
3936     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3937     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3938                            100, 100, 200, 200, 0, 0, 0, NULL);
3939     ok (hwnd != 0, "Failed to create popup window\n");
3940     ok(IsZoomed(hwnd), "window should be maximized\n");
3941     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3942     trace("done\n");
3943     DestroyWindow(hwnd);
3944     flush_sequence();
3945
3946     /* Test 4:
3947      * 1. Create visible popup window.
3948      * 2. Maximize it.
3949      */
3950     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3951     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3952                            100, 100, 200, 200, 0, 0, 0, NULL);
3953     ok (hwnd != 0, "Failed to create popup window\n");
3954     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
3955     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
3956     trace("done\n");
3957
3958     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3959     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3960     ok(IsZoomed(hwnd), "window should be maximized\n");
3961     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3962     trace("done\n");
3963     DestroyWindow(hwnd);
3964     flush_sequence();
3965 }
3966
3967 static void test_sys_menu(void)
3968 {
3969     HWND hwnd;
3970     HMENU hmenu;
3971     UINT state;
3972
3973     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3974                            100, 100, 200, 200, 0, 0, 0, NULL);
3975     ok (hwnd != 0, "Failed to create overlapped window\n");
3976
3977     flush_sequence();
3978
3979     /* test existing window without CS_NOCLOSE style */
3980     hmenu = GetSystemMenu(hwnd, FALSE);
3981     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3982
3983     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3984     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3985     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3986
3987     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3988     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3989
3990     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3991     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3992     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3993
3994     EnableMenuItem(hmenu, SC_CLOSE, 0);
3995     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3996
3997     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3998     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3999     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4000
4001     /* test whether removing WS_SYSMENU destroys a system menu */
4002     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4003     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4004     flush_sequence();
4005     hmenu = GetSystemMenu(hwnd, FALSE);
4006     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4007
4008     DestroyWindow(hwnd);
4009
4010     /* test new window with CS_NOCLOSE style */
4011     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4012                            100, 100, 200, 200, 0, 0, 0, NULL);
4013     ok (hwnd != 0, "Failed to create overlapped window\n");
4014
4015     hmenu = GetSystemMenu(hwnd, FALSE);
4016     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4017
4018     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4019     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4020
4021     DestroyWindow(hwnd);
4022
4023     /* test new window without WS_SYSMENU style */
4024     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4025                            100, 100, 200, 200, 0, 0, 0, NULL);
4026     ok(hwnd != 0, "Failed to create overlapped window\n");
4027
4028     hmenu = GetSystemMenu(hwnd, FALSE);
4029     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4030
4031     DestroyWindow(hwnd);
4032 }
4033
4034 /* For shown WS_OVERLAPPEDWINDOW */
4035 static const struct message WmSetIcon_1[] = {
4036     { WM_SETICON, sent },
4037     { 0x00AE, sent|defwinproc|optional }, /* XP */
4038     { WM_GETTEXT, sent|defwinproc|optional },
4039     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4040     { 0 }
4041 };
4042
4043 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4044 static const struct message WmSetIcon_2[] = {
4045     { WM_SETICON, sent },
4046     { 0 }
4047 };
4048
4049 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4050 static const struct message WmInitEndSession[] = {
4051     { 0x003B, sent },
4052     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4053     { 0 }
4054 };
4055
4056 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4057 static const struct message WmInitEndSession_2[] = {
4058     { 0x003B, sent },
4059     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4060     { 0 }
4061 };
4062
4063 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4064 static const struct message WmInitEndSession_3[] = {
4065     { 0x003B, sent },
4066     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4067     { 0 }
4068 };
4069
4070 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4071 static const struct message WmInitEndSession_4[] = {
4072     { 0x003B, sent },
4073     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4074     { 0 }
4075 };
4076
4077 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4078 static const struct message WmInitEndSession_5[] = {
4079     { 0x003B, sent },
4080     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 1, ENDSESSION_LOGOFF },
4081     { 0 }
4082 };
4083
4084 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4085 {
4086     DWORD ret;
4087     MSG msg;
4088
4089     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4090     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4091
4092     PostMessageA(hwnd, WM_USER, 0, 0);
4093
4094     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4095     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4096
4097     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4098     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4099
4100     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4101     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4102
4103     PostMessageA(hwnd, WM_USER, 0, 0);
4104
4105     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4106     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4107
4108     ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4109     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4110
4111     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4112     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4113     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4114
4115     PostMessageA(hwnd, WM_USER, 0, 0);
4116
4117     /* new incoming message causes it to become signaled again */
4118     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4119     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4120
4121     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4122     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4123     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4124     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4125 }
4126
4127 /* test if we receive the right sequence of messages */
4128 static void test_messages(void)
4129 {
4130     HWND hwnd, hparent, hchild;
4131     HWND hchild2, hbutton;
4132     HMENU hmenu;
4133     MSG msg;
4134     LRESULT res;
4135
4136     flush_sequence();
4137
4138     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4139                            100, 100, 200, 200, 0, 0, 0, NULL);
4140     ok (hwnd != 0, "Failed to create overlapped window\n");
4141     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4142
4143     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4144     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4145     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4146
4147     /* test WM_SETREDRAW on a not visible top level window */
4148     test_WM_SETREDRAW(hwnd);
4149
4150     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4151     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4152     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4153
4154     ok(GetActiveWindow() == hwnd, "window should be active\n");
4155     ok(GetFocus() == hwnd, "window should have input focus\n");
4156     ShowWindow(hwnd, SW_HIDE);
4157     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4158
4159     ShowWindow(hwnd, SW_SHOW);
4160     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4161
4162     ShowWindow(hwnd, SW_HIDE);
4163     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4164
4165     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4166     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4167
4168     ShowWindow(hwnd, SW_RESTORE);
4169     ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
4170     flush_sequence();
4171
4172     ShowWindow(hwnd, SW_MINIMIZE);
4173     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4174     flush_sequence();
4175
4176     ShowWindow(hwnd, SW_RESTORE);
4177     ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4178     flush_sequence();
4179
4180     ShowWindow(hwnd, SW_SHOW);
4181     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4182
4183     ok(GetActiveWindow() == hwnd, "window should be active\n");
4184     ok(GetFocus() == hwnd, "window should have input focus\n");
4185     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4186     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4187     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4188     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4189
4190     /* test WM_SETREDRAW on a visible top level window */
4191     ShowWindow(hwnd, SW_SHOW);
4192     test_WM_SETREDRAW(hwnd);
4193
4194     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4195     test_scroll_messages(hwnd);
4196
4197     /* test resizing and moving */
4198     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4199     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4200     flush_events();
4201     flush_sequence();
4202     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4203     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4204     flush_events();
4205     flush_sequence();
4206     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
4207     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4208     flush_events();
4209     flush_sequence();
4210
4211     /* popups don't get WM_GETMINMAXINFO */
4212     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4213     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4214     flush_sequence();
4215     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4216     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4217
4218     DestroyWindow(hwnd);
4219     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4220
4221     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4222                               100, 100, 200, 200, 0, 0, 0, NULL);
4223     ok (hparent != 0, "Failed to create parent window\n");
4224     flush_sequence();
4225
4226     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4227                              0, 0, 10, 10, hparent, 0, 0, NULL);
4228     ok (hchild != 0, "Failed to create child window\n");
4229     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4230     DestroyWindow(hchild);
4231     flush_sequence();
4232
4233     /* visible child window with a caption */
4234     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4235                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4236                              0, 0, 10, 10, hparent, 0, 0, NULL);
4237     ok (hchild != 0, "Failed to create child window\n");
4238     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4239
4240     trace("testing scroll APIs on a visible child window %p\n", hchild);
4241     test_scroll_messages(hchild);
4242
4243     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4244     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4245
4246     DestroyWindow(hchild);
4247     flush_sequence();
4248
4249     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4250                              0, 0, 10, 10, hparent, 0, 0, NULL);
4251     ok (hchild != 0, "Failed to create child window\n");
4252     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4253     
4254     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4255                                100, 100, 50, 50, hparent, 0, 0, NULL);
4256     ok (hchild2 != 0, "Failed to create child2 window\n");
4257     flush_sequence();
4258
4259     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4260                               0, 100, 50, 50, hchild, 0, 0, NULL);
4261     ok (hbutton != 0, "Failed to create button window\n");
4262
4263     /* test WM_SETREDRAW on a not visible child window */
4264     test_WM_SETREDRAW(hchild);
4265
4266     ShowWindow(hchild, SW_SHOW);
4267     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4268
4269     /* check parent messages too */
4270     log_all_parent_messages++;
4271     ShowWindow(hchild, SW_HIDE);
4272     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4273     log_all_parent_messages--;
4274
4275     ShowWindow(hchild, SW_SHOW);
4276     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4277
4278     ShowWindow(hchild, SW_HIDE);
4279     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4280
4281     ShowWindow(hchild, SW_SHOW);
4282     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4283
4284     /* test WM_SETREDRAW on a visible child window */
4285     test_WM_SETREDRAW(hchild);
4286
4287     log_all_parent_messages++;
4288     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4289     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4290     log_all_parent_messages--;
4291
4292     ShowWindow(hchild, SW_HIDE);
4293     flush_sequence();
4294     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4295     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4296
4297     ShowWindow(hchild, SW_HIDE);
4298     flush_sequence();
4299     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4300     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4301
4302     /* DestroyWindow sequence below expects that a child has focus */
4303     SetFocus(hchild);
4304     flush_sequence();
4305
4306     DestroyWindow(hchild);
4307     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4308     DestroyWindow(hchild2);
4309     DestroyWindow(hbutton);
4310
4311     flush_sequence();
4312     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4313                              0, 0, 100, 100, hparent, 0, 0, NULL);
4314     ok (hchild != 0, "Failed to create child popup window\n");
4315     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4316     DestroyWindow(hchild);
4317
4318     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4319     flush_sequence();
4320     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4321                              0, 0, 100, 100, hparent, 0, 0, NULL);
4322     ok (hchild != 0, "Failed to create popup window\n");
4323     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4324     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4325     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4326     flush_sequence();
4327     ShowWindow(hchild, SW_SHOW);
4328     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4329     flush_sequence();
4330     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4331     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4332     flush_sequence();
4333     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4334     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", TRUE);
4335     DestroyWindow(hchild);
4336
4337     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4338      * changes nothing in message sequences.
4339      */
4340     flush_sequence();
4341     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4342                              0, 0, 100, 100, hparent, 0, 0, NULL);
4343     ok (hchild != 0, "Failed to create popup window\n");
4344     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4345     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4346     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4347     flush_sequence();
4348     ShowWindow(hchild, SW_SHOW);
4349     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4350     flush_sequence();
4351     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4352     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4353     DestroyWindow(hchild);
4354
4355     flush_sequence();
4356     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4357                            0, 0, 100, 100, hparent, 0, 0, NULL);
4358     ok(hwnd != 0, "Failed to create custom dialog window\n");
4359     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4360
4361     /*
4362     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4363     test_scroll_messages(hwnd);
4364     */
4365
4366     flush_sequence();
4367
4368     test_def_id = 1;
4369     SendMessage(hwnd, WM_NULL, 0, 0);
4370
4371     flush_sequence();
4372     after_end_dialog = 1;
4373     EndDialog( hwnd, 0 );
4374     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4375
4376     DestroyWindow(hwnd);
4377     after_end_dialog = 0;
4378     test_def_id = 0;
4379
4380     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4381                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4382     ok(hwnd != 0, "Failed to create custom dialog window\n");
4383     flush_sequence();
4384     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4385     ShowWindow(hwnd, SW_SHOW);
4386     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4387     DestroyWindow(hwnd);
4388
4389     flush_sequence();
4390     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4391     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4392
4393     DestroyWindow(hparent);
4394     flush_sequence();
4395
4396     /* Message sequence for SetMenu */
4397     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4398     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4399
4400     hmenu = CreateMenu();
4401     ok (hmenu != 0, "Failed to create menu\n");
4402     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4403     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4404                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4405     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4406     ok (SetMenu(hwnd, 0), "SetMenu\n");
4407     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4408     ok (SetMenu(hwnd, 0), "SetMenu\n");
4409     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4410     ShowWindow(hwnd, SW_SHOW);
4411     UpdateWindow( hwnd );
4412     flush_events();
4413     flush_sequence();
4414     ok (SetMenu(hwnd, 0), "SetMenu\n");
4415     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4416     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4417     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4418
4419     UpdateWindow( hwnd );
4420     flush_events();
4421     flush_sequence();
4422     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4423     flush_events();
4424     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4425
4426     DestroyWindow(hwnd);
4427     flush_sequence();
4428
4429     /* Message sequence for EnableWindow */
4430     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4431                               100, 100, 200, 200, 0, 0, 0, NULL);
4432     ok (hparent != 0, "Failed to create parent window\n");
4433     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4434                              0, 0, 10, 10, hparent, 0, 0, NULL);
4435     ok (hchild != 0, "Failed to create child window\n");
4436
4437     SetFocus(hchild);
4438     flush_events();
4439     flush_sequence();
4440
4441     EnableWindow(hparent, FALSE);
4442     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4443
4444     EnableWindow(hparent, TRUE);
4445     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4446
4447     flush_events();
4448     flush_sequence();
4449
4450     test_MsgWaitForMultipleObjects(hparent);
4451
4452     /* the following test causes an exception in user.exe under win9x */
4453     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4454     {
4455         DestroyWindow(hparent);
4456         flush_sequence();
4457         return;
4458     }
4459     PostMessageW( hparent, WM_USER+1, 0, 0 );
4460     /* PeekMessage(NULL) fails, but still removes the message */
4461     SetLastError(0xdeadbeef);
4462     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4463     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4464         GetLastError() == 0xdeadbeef, /* NT4 */
4465         "last error is %d\n", GetLastError() );
4466     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4467     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4468
4469     DestroyWindow(hchild);
4470     DestroyWindow(hparent);
4471     flush_sequence();
4472
4473     /* Message sequences for WM_SETICON */
4474     trace("testing WM_SETICON\n");
4475     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4476                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4477                            NULL, NULL, 0);
4478     ShowWindow(hwnd, SW_SHOW);
4479     UpdateWindow(hwnd);
4480     flush_events();
4481     flush_sequence();
4482     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4483     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4484
4485     ShowWindow(hwnd, SW_HIDE);
4486     flush_events();
4487     flush_sequence();
4488     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4489     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4490     DestroyWindow(hwnd);
4491     flush_sequence();
4492
4493     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4494                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4495                            NULL, NULL, 0);
4496     ShowWindow(hwnd, SW_SHOW);
4497     UpdateWindow(hwnd);
4498     flush_events();
4499     flush_sequence();
4500     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4501     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4502
4503     ShowWindow(hwnd, SW_HIDE);
4504     flush_events();
4505     flush_sequence();
4506     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4507     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4508
4509     flush_sequence();
4510     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4511     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4512     todo_wine
4513     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4514     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4515     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4516     todo_wine
4517     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4518     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4519     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4520     todo_wine
4521     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4522
4523     flush_sequence();
4524     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4525     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4526     todo_wine
4527     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4528     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4529     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4530     todo_wine
4531     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4532
4533     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4534     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4535     todo_wine
4536     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4537
4538     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4539     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4540     todo_wine
4541     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4542
4543     DestroyWindow(hwnd);
4544     flush_sequence();
4545 }
4546
4547 static void invisible_parent_tests(void)
4548 {
4549     HWND hparent, hchild;
4550
4551     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4552                               100, 100, 200, 200, 0, 0, 0, NULL);
4553     ok (hparent != 0, "Failed to create parent window\n");
4554     flush_sequence();
4555
4556     /* test showing child with hidden parent */
4557
4558     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4559                              0, 0, 10, 10, hparent, 0, 0, NULL);
4560     ok (hchild != 0, "Failed to create child window\n");
4561     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4562
4563     ShowWindow( hchild, SW_MINIMIZE );
4564     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4565     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4566     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4567
4568     /* repeat */
4569     flush_events();
4570     flush_sequence();
4571     ShowWindow( hchild, SW_MINIMIZE );
4572     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4573
4574     DestroyWindow(hchild);
4575     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4576                              0, 0, 10, 10, hparent, 0, 0, NULL);
4577     flush_sequence();
4578
4579     ShowWindow( hchild, SW_MAXIMIZE );
4580     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4581     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4582     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4583
4584     /* repeat */
4585     flush_events();
4586     flush_sequence();
4587     ShowWindow( hchild, SW_MAXIMIZE );
4588     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4589
4590     DestroyWindow(hchild);
4591     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4592                              0, 0, 10, 10, hparent, 0, 0, NULL);
4593     flush_sequence();
4594
4595     ShowWindow( hchild, SW_RESTORE );
4596     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4597     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4598     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4599
4600     DestroyWindow(hchild);
4601     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4602                              0, 0, 10, 10, hparent, 0, 0, NULL);
4603     flush_sequence();
4604
4605     ShowWindow( hchild, SW_SHOWMINIMIZED );
4606     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4607     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4608     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4609
4610     /* repeat */
4611     flush_events();
4612     flush_sequence();
4613     ShowWindow( hchild, SW_SHOWMINIMIZED );
4614     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4615
4616     DestroyWindow(hchild);
4617     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4618                              0, 0, 10, 10, hparent, 0, 0, NULL);
4619     flush_sequence();
4620
4621     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4622     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4623     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4624     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4625     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4626
4627     DestroyWindow(hchild);
4628     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4629                              0, 0, 10, 10, hparent, 0, 0, NULL);
4630     flush_sequence();
4631
4632     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4633     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4634     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4635     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4636
4637     /* repeat */
4638     flush_events();
4639     flush_sequence();
4640     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4641     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4642
4643     DestroyWindow(hchild);
4644     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4645                              0, 0, 10, 10, hparent, 0, 0, NULL);
4646     flush_sequence();
4647
4648     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4649     ShowWindow( hchild, SW_FORCEMINIMIZE );
4650     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4651 todo_wine {
4652     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4653 }
4654     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4655
4656     DestroyWindow(hchild);
4657     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4658                              0, 0, 10, 10, hparent, 0, 0, NULL);
4659     flush_sequence();
4660
4661     ShowWindow( hchild, SW_SHOWNA );
4662     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4663     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4664     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4665
4666     /* repeat */
4667     flush_events();
4668     flush_sequence();
4669     ShowWindow( hchild, SW_SHOWNA );
4670     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4671
4672     DestroyWindow(hchild);
4673     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4674                              0, 0, 10, 10, hparent, 0, 0, NULL);
4675     flush_sequence();
4676
4677     ShowWindow( hchild, SW_SHOW );
4678     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4679     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4680     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4681
4682     /* repeat */
4683     flush_events();
4684     flush_sequence();
4685     ShowWindow( hchild, SW_SHOW );
4686     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4687
4688     ShowWindow( hchild, SW_HIDE );
4689     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4690     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4691     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4692
4693     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4694     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4695     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4696     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4697
4698     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4699     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4700     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4701     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4702
4703     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4704     flush_sequence();
4705     DestroyWindow(hchild);
4706     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4707
4708     DestroyWindow(hparent);
4709     flush_sequence();
4710 }
4711
4712 /****************** button message test *************************/
4713 static const struct message WmSetFocusButtonSeq[] =
4714 {
4715     { HCBT_SETFOCUS, hook },
4716     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4717     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4718     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4719     { WM_SETFOCUS, sent|wparam, 0 },
4720     { WM_CTLCOLORBTN, sent|defwinproc },
4721     { 0 }
4722 };
4723 static const struct message WmKillFocusButtonSeq[] =
4724 {
4725     { HCBT_SETFOCUS, hook },
4726     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4727     { WM_KILLFOCUS, sent|wparam, 0 },
4728     { WM_CTLCOLORBTN, sent|defwinproc },
4729     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4730     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4731     { 0 }
4732 };
4733 static const struct message WmSetFocusStaticSeq[] =
4734 {
4735     { HCBT_SETFOCUS, hook },
4736     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4737     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4738     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4739     { WM_SETFOCUS, sent|wparam, 0 },
4740     { WM_CTLCOLORSTATIC, sent|defwinproc },
4741     { 0 }
4742 };
4743 static const struct message WmKillFocusStaticSeq[] =
4744 {
4745     { HCBT_SETFOCUS, hook },
4746     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4747     { WM_KILLFOCUS, sent|wparam, 0 },
4748     { WM_CTLCOLORSTATIC, sent|defwinproc },
4749     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4750     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4751     { 0 }
4752 };
4753 static const struct message WmLButtonDownSeq[] =
4754 {
4755     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4756     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4757     { HCBT_SETFOCUS, hook },
4758     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4759     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4760     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4761     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4762     { WM_CTLCOLORBTN, sent|defwinproc },
4763     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4764     { WM_CTLCOLORBTN, sent|defwinproc },
4765     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4766     { 0 }
4767 };
4768 static const struct message WmLButtonUpSeq[] =
4769 {
4770     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4771     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4772     { WM_CTLCOLORBTN, sent|defwinproc },
4773     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4774     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4775     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4776     { 0 }
4777 };
4778 static const struct message WmSetFontButtonSeq[] =
4779 {
4780     { WM_SETFONT, sent },
4781     { WM_PAINT, sent },
4782     { WM_ERASEBKGND, sent|defwinproc|optional },
4783     { WM_CTLCOLORBTN, sent|defwinproc },
4784     { 0 }
4785 };
4786
4787 static WNDPROC old_button_proc;
4788
4789 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4790 {
4791     static long defwndproc_counter = 0;
4792     LRESULT ret;
4793     struct message msg;
4794
4795     trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4796
4797     /* explicitly ignore WM_GETICON message */
4798     if (message == WM_GETICON) return 0;
4799
4800     msg.message = message;
4801     msg.flags = sent|wparam|lparam;
4802     if (defwndproc_counter) msg.flags |= defwinproc;
4803     msg.wParam = wParam;
4804     msg.lParam = lParam;
4805     add_message(&msg);
4806
4807     if (message == BM_SETSTATE)
4808         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4809
4810     defwndproc_counter++;
4811     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4812     defwndproc_counter--;
4813
4814     return ret;
4815 }
4816
4817 static void subclass_button(void)
4818 {
4819     WNDCLASSA cls;
4820
4821     if (!GetClassInfoA(0, "button", &cls)) assert(0);
4822
4823     old_button_proc = cls.lpfnWndProc;
4824
4825     cls.hInstance = GetModuleHandle(0);
4826     cls.lpfnWndProc = button_hook_proc;
4827     cls.lpszClassName = "my_button_class";
4828     UnregisterClass(cls.lpszClassName, cls.hInstance);
4829     if (!RegisterClassA(&cls)) assert(0);
4830 }
4831
4832 static void test_button_messages(void)
4833 {
4834     static const struct
4835     {
4836         DWORD style;
4837         DWORD dlg_code;
4838         const struct message *setfocus;
4839         const struct message *killfocus;
4840     } button[] = {
4841         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4842           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4843         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4844           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4845         { BS_CHECKBOX, DLGC_BUTTON,
4846           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4847         { BS_AUTOCHECKBOX, DLGC_BUTTON,
4848           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4849         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4850           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4851         { BS_3STATE, DLGC_BUTTON,
4852           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4853         { BS_AUTO3STATE, DLGC_BUTTON,
4854           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4855         { BS_GROUPBOX, DLGC_STATIC,
4856           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4857         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4858           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4859         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4860           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4861         { BS_OWNERDRAW, DLGC_BUTTON,
4862           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4863     };
4864     unsigned int i;
4865     HWND hwnd;
4866     DWORD dlg_code;
4867     HFONT zfont;
4868
4869     subclass_button();
4870
4871     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
4872     {
4873         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
4874                                0, 0, 50, 14, 0, 0, 0, NULL);
4875         ok(hwnd != 0, "Failed to create button window\n");
4876
4877         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4878         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4879
4880         ShowWindow(hwnd, SW_SHOW);
4881         UpdateWindow(hwnd);
4882         SetFocus(0);
4883         flush_sequence();
4884
4885         trace("button style %08x\n", button[i].style);
4886         SetFocus(hwnd);
4887         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
4888
4889         SetFocus(0);
4890         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
4891
4892         DestroyWindow(hwnd);
4893     }
4894
4895     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
4896                            0, 0, 50, 14, 0, 0, 0, NULL);
4897     ok(hwnd != 0, "Failed to create button window\n");
4898
4899     SetFocus(0);
4900     flush_events();
4901     flush_sequence();
4902
4903     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
4904     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
4905
4906     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
4907     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
4908
4909     flush_sequence();
4910     zfont = (HFONT)GetStockObject(SYSTEM_FONT);
4911     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
4912     UpdateWindow(hwnd);
4913     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
4914
4915     DestroyWindow(hwnd);
4916 }
4917
4918 /****************** static message test *************************/
4919 static const struct message WmSetFontStaticSeq[] =
4920 {
4921     { WM_SETFONT, sent },
4922     { WM_PAINT, sent|defwinproc },
4923     { WM_ERASEBKGND, sent|defwinproc|optional },
4924     { WM_CTLCOLORSTATIC, sent|defwinproc },
4925     { 0 }
4926 };
4927
4928 static WNDPROC old_static_proc;
4929
4930 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4931 {
4932     static long defwndproc_counter = 0;
4933     LRESULT ret;
4934     struct message msg;
4935
4936     trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4937
4938     /* explicitly ignore WM_GETICON message */
4939     if (message == WM_GETICON) return 0;
4940
4941     msg.message = message;
4942     msg.flags = sent|wparam|lparam;
4943     if (defwndproc_counter) msg.flags |= defwinproc;
4944     msg.wParam = wParam;
4945     msg.lParam = lParam;
4946     add_message(&msg);
4947
4948     defwndproc_counter++;
4949     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
4950     defwndproc_counter--;
4951
4952     return ret;
4953 }
4954
4955 static void subclass_static(void)
4956 {
4957     WNDCLASSA cls;
4958
4959     if (!GetClassInfoA(0, "static", &cls)) assert(0);
4960
4961     old_static_proc = cls.lpfnWndProc;
4962
4963     cls.hInstance = GetModuleHandle(0);
4964     cls.lpfnWndProc = static_hook_proc;
4965     cls.lpszClassName = "my_static_class";
4966     UnregisterClass(cls.lpszClassName, cls.hInstance);
4967     if (!RegisterClassA(&cls)) assert(0);
4968 }
4969
4970 static void test_static_messages(void)
4971 {
4972     /* FIXME: make as comprehensive as the button message test */
4973     static const struct
4974     {
4975         DWORD style;
4976         DWORD dlg_code;
4977         const struct message *setfont;
4978     } static_ctrl[] = {
4979         { SS_LEFT, DLGC_STATIC,
4980           WmSetFontStaticSeq }
4981     };
4982     unsigned int i;
4983     HWND hwnd;
4984     DWORD dlg_code;
4985
4986     subclass_static();
4987
4988     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
4989     {
4990         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
4991                                0, 0, 50, 14, 0, 0, 0, NULL);
4992         ok(hwnd != 0, "Failed to create static window\n");
4993
4994         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4995         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4996
4997         ShowWindow(hwnd, SW_SHOW);
4998         UpdateWindow(hwnd);
4999         SetFocus(0);
5000         flush_sequence();
5001
5002         trace("static style %08x\n", static_ctrl[i].style);
5003         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5004         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5005
5006         DestroyWindow(hwnd);
5007     }
5008 }
5009
5010 /****************** ComboBox message test *************************/
5011 #define ID_COMBOBOX 0x000f
5012
5013 static const struct message WmKeyDownComboSeq[] =
5014 {
5015     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5016     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5017     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5018     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5019     { WM_CTLCOLOREDIT, sent|parent },
5020     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5021     { 0 }
5022 };
5023
5024 static WNDPROC old_combobox_proc;
5025
5026 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5027 {
5028     static long defwndproc_counter = 0;
5029     LRESULT ret;
5030     struct message msg;
5031
5032     /* do not log painting messages */
5033     if (message != WM_PAINT &&
5034         message != WM_NCPAINT &&
5035         message != WM_SYNCPAINT &&
5036         message != WM_ERASEBKGND &&
5037         message != WM_NCHITTEST &&
5038         message != WM_GETTEXT &&
5039         message != WM_GETICON &&
5040         message != WM_DEVICECHANGE)
5041     {
5042         trace("combo: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5043
5044         msg.message = message;
5045         msg.flags = sent|wparam|lparam;
5046         if (defwndproc_counter) msg.flags |= defwinproc;
5047         msg.wParam = wParam;
5048         msg.lParam = lParam;
5049         add_message(&msg);
5050     }
5051
5052     defwndproc_counter++;
5053     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5054     defwndproc_counter--;
5055
5056     return ret;
5057 }
5058
5059 static void subclass_combobox(void)
5060 {
5061     WNDCLASSA cls;
5062
5063     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5064
5065     old_combobox_proc = cls.lpfnWndProc;
5066
5067     cls.hInstance = GetModuleHandle(0);
5068     cls.lpfnWndProc = combobox_hook_proc;
5069     cls.lpszClassName = "my_combobox_class";
5070     UnregisterClass(cls.lpszClassName, cls.hInstance);
5071     if (!RegisterClassA(&cls)) assert(0);
5072 }
5073
5074 static void test_combobox_messages(void)
5075 {
5076     HWND parent, combo;
5077     LRESULT ret;
5078
5079     subclass_combobox();
5080
5081     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5082                              100, 100, 200, 200, 0, 0, 0, NULL);
5083     ok(parent != 0, "Failed to create parent window\n");
5084     flush_sequence();
5085
5086     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5087                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5088     ok(combo != 0, "Failed to create combobox window\n");
5089
5090     UpdateWindow(combo);
5091
5092     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5093     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5094
5095     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5096     ok(ret == 0, "expected 0, got %ld\n", ret);
5097     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5098     ok(ret == 1, "expected 1, got %ld\n", ret);
5099     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5100     ok(ret == 2, "expected 2, got %ld\n", ret);
5101
5102     SendMessage(combo, CB_SETCURSEL, 0, 0);
5103     SetFocus(combo);
5104     flush_sequence();
5105
5106     log_all_parent_messages++;
5107     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5108     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5109     log_all_parent_messages--;
5110     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5111
5112     DestroyWindow(combo);
5113     DestroyWindow(parent);
5114 }
5115
5116 /****************** WM_IME_KEYDOWN message test *******************/
5117
5118 static const struct message WmImeKeydownMsgSeq_0[] =
5119 {
5120     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5121     { WM_CHAR, wparam, 'A' },
5122     { 0 }
5123 };
5124
5125 static const struct message WmImeKeydownMsgSeq_1[] =
5126 {
5127     { WM_KEYDOWN, wparam, VK_RETURN },
5128     { WM_CHAR,    wparam, VK_RETURN },
5129     { 0 }
5130 };
5131
5132 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5133 {
5134     struct message msg;
5135
5136     trace("wmime_keydown_procA: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5137
5138     msg.message = message;
5139     msg.flags = wparam|lparam;
5140     msg.wParam = wParam;
5141     msg.lParam = lParam;
5142     add_message(&msg);
5143
5144     return DefWindowProcA(hwnd, message, wParam, lParam);
5145 }
5146
5147 static void register_wmime_keydown_class(void)
5148 {
5149     WNDCLASSA cls;
5150
5151     ZeroMemory(&cls, sizeof(WNDCLASSA));
5152     cls.lpfnWndProc = wmime_keydown_procA;
5153     cls.hInstance = GetModuleHandleA(0);
5154     cls.lpszClassName = "wmime_keydown_class";
5155     if (!RegisterClassA(&cls)) assert(0);
5156 }
5157
5158 void test_wmime_keydown_message(void)
5159 {
5160     HWND hwnd;
5161     MSG msg;
5162
5163     trace("Message sequences by WM_IME_KEYDOWN\n");
5164
5165     register_wmime_keydown_class();
5166     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5167                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5168                            NULL, NULL, 0);
5169     flush_events();
5170     flush_sequence();
5171
5172     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5173     SendMessage(hwnd, WM_CHAR, 'A', 1);
5174     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5175
5176     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5177     {
5178         TranslateMessage(&msg);
5179         DispatchMessage(&msg);
5180     }
5181     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5182
5183     DestroyWindow(hwnd);
5184 }
5185
5186 /************* painting message test ********************/
5187
5188 void dump_region(HRGN hrgn)
5189 {
5190     DWORD i, size;
5191     RGNDATA *data = NULL;
5192     RECT *rect;
5193
5194     if (!hrgn)
5195     {
5196         printf( "null region\n" );
5197         return;
5198     }
5199     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5200     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5201     GetRegionData( hrgn, size, data );
5202     printf("%d rects:", data->rdh.nCount );
5203     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5204         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5205     printf("\n");
5206     HeapFree( GetProcessHeap(), 0, data );
5207 }
5208
5209 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5210 {
5211     INT ret;
5212     RECT r1, r2;
5213     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5214     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5215
5216     ret = GetUpdateRgn( hwnd, update, FALSE );
5217     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5218     if (ret == NULLREGION)
5219     {
5220         ok( !hrgn, "Update region shouldn't be empty\n" );
5221     }
5222     else
5223     {
5224         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5225         {
5226             ok( 0, "Regions are different\n" );
5227             if (winetest_debug > 0)
5228             {
5229                 printf( "Update region: " );
5230                 dump_region( update );
5231                 printf( "Wanted region: " );
5232                 dump_region( hrgn );
5233             }
5234         }
5235     }
5236     GetRgnBox( update, &r1 );
5237     GetUpdateRect( hwnd, &r2, FALSE );
5238     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5239         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5240         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5241
5242     DeleteObject( tmp );
5243     DeleteObject( update );
5244 }
5245
5246 static const struct message WmInvalidateRgn[] = {
5247     { WM_NCPAINT, sent },
5248     { WM_GETTEXT, sent|defwinproc|optional },
5249     { 0 }
5250 };
5251
5252 static const struct message WmGetUpdateRect[] = {
5253     { WM_NCPAINT, sent },
5254     { WM_GETTEXT, sent|defwinproc|optional },
5255     { WM_PAINT, sent },
5256     { 0 }
5257 };
5258
5259 static const struct message WmInvalidateFull[] = {
5260     { WM_NCPAINT, sent|wparam, 1 },
5261     { WM_GETTEXT, sent|defwinproc|optional },
5262     { 0 }
5263 };
5264
5265 static const struct message WmInvalidateErase[] = {
5266     { WM_NCPAINT, sent|wparam, 1 },
5267     { WM_GETTEXT, sent|defwinproc|optional },
5268     { WM_ERASEBKGND, sent },
5269     { 0 }
5270 };
5271
5272 static const struct message WmInvalidatePaint[] = {
5273     { WM_PAINT, sent },
5274     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5275     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5276     { 0 }
5277 };
5278
5279 static const struct message WmInvalidateErasePaint[] = {
5280     { WM_PAINT, sent },
5281     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5282     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5283     { WM_ERASEBKGND, sent|beginpaint },
5284     { 0 }
5285 };
5286
5287 static const struct message WmInvalidateErasePaint2[] = {
5288     { WM_PAINT, sent },
5289     { WM_NCPAINT, sent|beginpaint },
5290     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5291     { WM_ERASEBKGND, sent|beginpaint },
5292     { 0 }
5293 };
5294
5295 static const struct message WmErase[] = {
5296     { WM_ERASEBKGND, sent },
5297     { 0 }
5298 };
5299
5300 static const struct message WmPaint[] = {
5301     { WM_PAINT, sent },
5302     { 0 }
5303 };
5304
5305 static const struct message WmParentOnlyPaint[] = {
5306     { WM_PAINT, sent|parent },
5307     { 0 }
5308 };
5309
5310 static const struct message WmInvalidateParent[] = {
5311     { WM_NCPAINT, sent|parent },
5312     { WM_GETTEXT, sent|defwinproc|parent|optional },
5313     { WM_ERASEBKGND, sent|parent },
5314     { 0 }
5315 };
5316
5317 static const struct message WmInvalidateParentChild[] = {
5318     { WM_NCPAINT, sent|parent },
5319     { WM_GETTEXT, sent|defwinproc|parent|optional },
5320     { WM_ERASEBKGND, sent|parent },
5321     { WM_NCPAINT, sent },
5322     { WM_GETTEXT, sent|defwinproc|optional },
5323     { WM_ERASEBKGND, sent },
5324     { 0 }
5325 };
5326
5327 static const struct message WmInvalidateParentChild2[] = {
5328     { WM_ERASEBKGND, sent|parent },
5329     { WM_NCPAINT, sent },
5330     { WM_GETTEXT, sent|defwinproc|optional },
5331     { WM_ERASEBKGND, sent },
5332     { 0 }
5333 };
5334
5335 static const struct message WmParentPaint[] = {
5336     { WM_PAINT, sent|parent },
5337     { WM_PAINT, sent },
5338     { 0 }
5339 };
5340
5341 static const struct message WmParentPaintNc[] = {
5342     { WM_PAINT, sent|parent },
5343     { WM_PAINT, sent },
5344     { WM_NCPAINT, sent|beginpaint },
5345     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5346     { WM_ERASEBKGND, sent|beginpaint },
5347     { 0 }
5348 };
5349
5350 static const struct message WmChildPaintNc[] = {
5351     { WM_PAINT, sent },
5352     { WM_NCPAINT, sent|beginpaint },
5353     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5354     { WM_ERASEBKGND, sent|beginpaint },
5355     { 0 }
5356 };
5357
5358 static const struct message WmParentErasePaint[] = {
5359     { WM_PAINT, sent|parent },
5360     { WM_NCPAINT, sent|parent|beginpaint },
5361     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5362     { WM_ERASEBKGND, sent|parent|beginpaint },
5363     { WM_PAINT, sent },
5364     { WM_NCPAINT, sent|beginpaint },
5365     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5366     { WM_ERASEBKGND, sent|beginpaint },
5367     { 0 }
5368 };
5369
5370 static const struct message WmParentOnlyNcPaint[] = {
5371     { WM_PAINT, sent|parent },
5372     { WM_NCPAINT, sent|parent|beginpaint },
5373     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5374     { 0 }
5375 };
5376
5377 static const struct message WmSetParentStyle[] = {
5378     { WM_STYLECHANGING, sent|parent },
5379     { WM_STYLECHANGED, sent|parent },
5380     { 0 }
5381 };
5382
5383 static void test_paint_messages(void)
5384 {
5385     BOOL ret;
5386     RECT rect;
5387     POINT pt;
5388     MSG msg;
5389     HWND hparent, hchild;
5390     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5391     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5392     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5393                                 100, 100, 200, 200, 0, 0, 0, NULL);
5394     ok (hwnd != 0, "Failed to create overlapped window\n");
5395
5396     ShowWindow( hwnd, SW_SHOW );
5397     UpdateWindow( hwnd );
5398     flush_events();
5399     flush_sequence();
5400
5401     check_update_rgn( hwnd, 0 );
5402     SetRectRgn( hrgn, 10, 10, 20, 20 );
5403     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5404     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5405     check_update_rgn( hwnd, hrgn );
5406     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5407     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5408     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5409     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5410     check_update_rgn( hwnd, hrgn );
5411     /* validate everything */
5412     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5413     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5414     check_update_rgn( hwnd, 0 );
5415
5416     /* test empty region */
5417     SetRectRgn( hrgn, 10, 10, 10, 15 );
5418     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5419     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5420     check_update_rgn( hwnd, 0 );
5421     /* test empty rect */
5422     SetRect( &rect, 10, 10, 10, 15 );
5423     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5424     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5425     check_update_rgn( hwnd, 0 );
5426
5427     /* flush pending messages */
5428     flush_events();
5429     flush_sequence();
5430
5431     GetClientRect( hwnd, &rect );
5432     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5433     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5434      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5435      */
5436     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5437     SetRectEmpty( &rect );
5438     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5439     check_update_rgn( hwnd, hrgn );
5440     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5441     flush_events();
5442     ok_sequence( WmPaint, "Paint", FALSE );
5443     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5444     check_update_rgn( hwnd, 0 );
5445
5446     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5447      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5448      */
5449     trace("testing ValidateRect(0, NULL)\n");
5450     SetRectEmpty( &rect );
5451     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
5452     check_update_rgn( hwnd, hrgn );
5453     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5454     flush_events();
5455     ok_sequence( WmPaint, "Paint", FALSE );
5456     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5457     check_update_rgn( hwnd, 0 );
5458
5459     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5460     SetLastError(0xdeadbeef);
5461     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5462     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5463        "wrong error code %d\n", GetLastError());
5464     check_update_rgn( hwnd, 0 );
5465     flush_events();
5466     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5467
5468     trace("testing ValidateRgn(0, NULL)\n");
5469     SetLastError(0xdeadbeef);
5470     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5471     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
5472     check_update_rgn( hwnd, 0 );
5473     flush_events();
5474     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5475
5476     /* now with frame */
5477     SetRectRgn( hrgn, -5, -5, 20, 20 );
5478
5479     /* flush pending messages */
5480     flush_events();
5481     flush_sequence();
5482     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5483     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5484
5485     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5486     check_update_rgn( hwnd, hrgn );
5487
5488     flush_sequence();
5489     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5490     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5491
5492     flush_sequence();
5493     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5494     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5495
5496     GetClientRect( hwnd, &rect );
5497     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5498     check_update_rgn( hwnd, hrgn );
5499
5500     flush_sequence();
5501     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5502     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5503
5504     flush_sequence();
5505     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5506     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5507     check_update_rgn( hwnd, 0 );
5508
5509     flush_sequence();
5510     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5511     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5512     check_update_rgn( hwnd, 0 );
5513
5514     flush_sequence();
5515     SetRectRgn( hrgn, 0, 0, 100, 100 );
5516     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5517     SetRectRgn( hrgn, 0, 0, 50, 100 );
5518     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5519     SetRectRgn( hrgn, 50, 0, 100, 100 );
5520     check_update_rgn( hwnd, hrgn );
5521     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5522     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5523     check_update_rgn( hwnd, 0 );
5524
5525     flush_sequence();
5526     SetRectRgn( hrgn, 0, 0, 100, 100 );
5527     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5528     SetRectRgn( hrgn, 0, 0, 100, 50 );
5529     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5530     ok_sequence( WmErase, "Erase", FALSE );
5531     SetRectRgn( hrgn, 0, 50, 100, 100 );
5532     check_update_rgn( hwnd, hrgn );
5533
5534     flush_sequence();
5535     SetRectRgn( hrgn, 0, 0, 100, 100 );
5536     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5537     SetRectRgn( hrgn, 0, 0, 50, 50 );
5538     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5539     ok_sequence( WmPaint, "Paint", FALSE );
5540
5541     flush_sequence();
5542     SetRectRgn( hrgn, -4, -4, -2, -2 );
5543     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5544     SetRectRgn( hrgn, -200, -200, -198, -198 );
5545     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5546     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5547
5548     flush_sequence();
5549     SetRectRgn( hrgn, -4, -4, -2, -2 );
5550     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5551     SetRectRgn( hrgn, -4, -4, -3, -3 );
5552     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5553     SetRectRgn( hrgn, 0, 0, 1, 1 );
5554     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5555     ok_sequence( WmPaint, "Paint", FALSE );
5556
5557     flush_sequence();
5558     SetRectRgn( hrgn, -4, -4, -1, -1 );
5559     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5560     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5561     /* make sure no WM_PAINT was generated */
5562     flush_events();
5563     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5564
5565     flush_sequence();
5566     SetRectRgn( hrgn, -4, -4, -1, -1 );
5567     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5568     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5569     {
5570         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5571         {
5572             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5573             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5574             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5575             ret = GetUpdateRect( hwnd, &rect, FALSE );
5576             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5577             /* this will send WM_NCPAINT and validate the non client area */
5578             ret = GetUpdateRect( hwnd, &rect, TRUE );
5579             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5580         }
5581         DispatchMessage( &msg );
5582     }
5583     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5584
5585     DestroyWindow( hwnd );
5586
5587     /* now test with a child window */
5588
5589     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5590                               100, 100, 200, 200, 0, 0, 0, NULL);
5591     ok (hparent != 0, "Failed to create parent window\n");
5592
5593     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5594                            10, 10, 100, 100, hparent, 0, 0, NULL);
5595     ok (hchild != 0, "Failed to create child window\n");
5596
5597     ShowWindow( hparent, SW_SHOW );
5598     UpdateWindow( hparent );
5599     UpdateWindow( hchild );
5600     flush_events();
5601     flush_sequence();
5602     log_all_parent_messages++;
5603
5604     SetRect( &rect, 0, 0, 50, 50 );
5605     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5606     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5607     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5608
5609     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5610     pt.x = pt.y = 0;
5611     MapWindowPoints( hchild, hparent, &pt, 1 );
5612     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5613     check_update_rgn( hchild, hrgn );
5614     SetRectRgn( hrgn, 0, 0, 50, 50 );
5615     check_update_rgn( hparent, hrgn );
5616     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5617     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5618     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5619     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5620
5621     flush_events();
5622     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5623
5624     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5625     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5626     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5627     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5628     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5629
5630     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5631     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5632     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5633
5634     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5635     flush_sequence();
5636     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5637     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5638     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5639
5640     /* flush all paint messages */
5641     flush_events();
5642     flush_sequence();
5643
5644     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5645     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5646     SetRectRgn( hrgn, 0, 0, 50, 50 );
5647     check_update_rgn( hparent, hrgn );
5648     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5649     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5650     SetRectRgn( hrgn, 0, 0, 50, 50 );
5651     check_update_rgn( hparent, hrgn );
5652
5653     /* flush all paint messages */
5654     flush_events();
5655     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5656     flush_sequence();
5657
5658     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5659     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5660     SetRectRgn( hrgn, 0, 0, 50, 50 );
5661     check_update_rgn( hparent, hrgn );
5662     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5663     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5664     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5665     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5666     check_update_rgn( hparent, hrgn );
5667     /* flush all paint messages */
5668     flush_events();
5669     flush_sequence();
5670
5671     /* same as above but parent gets completely validated */
5672     SetRect( &rect, 20, 20, 30, 30 );
5673     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5674     SetRectRgn( hrgn, 20, 20, 30, 30 );
5675     check_update_rgn( hparent, hrgn );
5676     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5677     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5678     check_update_rgn( hparent, 0 );  /* no update region */
5679     flush_events();
5680     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
5681
5682     /* make sure RDW_VALIDATE on child doesn't have the same effect */
5683     flush_sequence();
5684     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5685     SetRectRgn( hrgn, 20, 20, 30, 30 );
5686     check_update_rgn( hparent, hrgn );
5687     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5688     SetRectRgn( hrgn, 20, 20, 30, 30 );
5689     check_update_rgn( hparent, hrgn );
5690
5691     /* same as above but normal WM_PAINT doesn't validate parent */
5692     flush_sequence();
5693     SetRect( &rect, 20, 20, 30, 30 );
5694     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5695     SetRectRgn( hrgn, 20, 20, 30, 30 );
5696     check_update_rgn( hparent, hrgn );
5697     /* no WM_PAINT in child while parent still pending */
5698     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5699     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5700     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5701     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5702
5703     flush_sequence();
5704     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5705     /* no WM_PAINT in child while parent still pending */
5706     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5707     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5708     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5709     /* now that parent is valid child should get WM_PAINT */
5710     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5711     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5712     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5713     ok_sequence( WmEmptySeq, "No other message", FALSE );
5714
5715     /* same thing with WS_CLIPCHILDREN in parent */
5716     flush_sequence();
5717     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5718     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5719     /* changing style invalidates non client area, but we need to invalidate something else to see it */
5720     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5721     ok_sequence( WmEmptySeq, "No message", FALSE );
5722     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5723     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5724
5725     flush_sequence();
5726     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5727     SetRectRgn( hrgn, 20, 20, 30, 30 );
5728     check_update_rgn( hparent, hrgn );
5729     /* no WM_PAINT in child while parent still pending */
5730     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5731     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5732     /* WM_PAINT in parent first */
5733     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5734     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5735
5736     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5737     flush_sequence();
5738     SetRect( &rect, 0, 0, 30, 30 );
5739     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5740     SetRectRgn( hrgn, 0, 0, 30, 30 );
5741     check_update_rgn( hparent, hrgn );
5742     flush_events();
5743     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5744
5745     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5746     flush_sequence();
5747     SetRect( &rect, -10, 0, 30, 30 );
5748     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5749     SetRect( &rect, 0, 0, 20, 20 );
5750     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5751     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5752     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5753
5754     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5755     flush_sequence();
5756     SetRect( &rect, -10, 0, 30, 30 );
5757     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5758     SetRect( &rect, 0, 0, 100, 100 );
5759     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5760     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5761     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5762     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5763     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5764
5765     /* test RDW_INTERNALPAINT behavior */
5766
5767     flush_sequence();
5768     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5769     flush_events();
5770     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5771
5772     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5773     flush_events();
5774     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5775
5776     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5777     flush_events();
5778     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5779
5780     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5781     UpdateWindow( hparent );
5782     flush_events();
5783     flush_sequence();
5784     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5785     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5786     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5787                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5788     flush_events();
5789     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5790
5791     UpdateWindow( hparent );
5792     flush_events();
5793     flush_sequence();
5794     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5795     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5796     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5797                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5798     flush_events();
5799     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5800
5801     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5802     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5803     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5804     flush_events();
5805     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5806
5807     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5808     UpdateWindow( hparent );
5809     flush_events();
5810     flush_sequence();
5811     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5812     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5813     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5814                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5815     flush_events();
5816     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5817
5818     UpdateWindow( hparent );
5819     flush_events();
5820     flush_sequence();
5821     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5822     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5823     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5824                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5825     flush_events();
5826     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5827
5828     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
5829     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
5830
5831     UpdateWindow( hparent );
5832     flush_events();
5833     flush_sequence();
5834     trace("testing SetWindowPos(-10000, -10000) on child\n");
5835     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
5836     check_update_rgn( hchild, 0 );
5837     flush_events();
5838
5839 #if 0 /* this one doesn't pass under Wine yet */
5840     UpdateWindow( hparent );
5841     flush_events();
5842     flush_sequence();
5843     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
5844     ShowWindow( hchild, SW_MINIMIZE );
5845     check_update_rgn( hchild, 0 );
5846     flush_events();
5847 #endif
5848
5849     UpdateWindow( hparent );
5850     flush_events();
5851     flush_sequence();
5852     trace("testing SetWindowPos(-10000, -10000) on parent\n");
5853     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
5854     check_update_rgn( hparent, 0 );
5855     flush_events();
5856
5857     log_all_parent_messages--;
5858     DestroyWindow( hparent );
5859     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5860
5861     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
5862
5863     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
5864                               100, 100, 200, 200, 0, 0, 0, NULL);
5865     ok (hparent != 0, "Failed to create parent window\n");
5866
5867     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5868                            10, 10, 100, 100, hparent, 0, 0, NULL);
5869     ok (hchild != 0, "Failed to create child window\n");
5870
5871     ShowWindow( hparent, SW_SHOW );
5872     UpdateWindow( hparent );
5873     UpdateWindow( hchild );
5874     flush_events();
5875     flush_sequence();
5876
5877     /* moving child outside of parent boundaries changes update region */
5878     SetRect( &rect, 0, 0, 40, 40 );
5879     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5880     SetRectRgn( hrgn, 0, 0, 40, 40 );
5881     check_update_rgn( hchild, hrgn );
5882     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
5883     SetRectRgn( hrgn, 10, 0, 40, 40 );
5884     check_update_rgn( hchild, hrgn );
5885     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
5886     SetRectRgn( hrgn, 10, 10, 40, 40 );
5887     check_update_rgn( hchild, hrgn );
5888
5889     /* moving parent off-screen does too */
5890     SetRect( &rect, 0, 0, 100, 100 );
5891     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
5892     SetRectRgn( hrgn, 0, 0, 100, 100 );
5893     check_update_rgn( hparent, hrgn );
5894     SetRectRgn( hrgn, 10, 10, 40, 40 );
5895     check_update_rgn( hchild, hrgn );
5896     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
5897     SetRectRgn( hrgn, 20, 20, 100, 100 );
5898     check_update_rgn( hparent, hrgn );
5899     SetRectRgn( hrgn, 30, 30, 40, 40 );
5900     check_update_rgn( hchild, hrgn );
5901
5902     /* invalidated region is cropped by the parent rects */
5903     SetRect( &rect, 0, 0, 50, 50 );
5904     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5905     SetRectRgn( hrgn, 30, 30, 50, 50 );
5906     check_update_rgn( hchild, hrgn );
5907
5908     DestroyWindow( hparent );
5909     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5910     flush_sequence();
5911
5912     DeleteObject( hrgn );
5913     DeleteObject( hrgn2 );
5914 }
5915
5916 struct wnd_event
5917 {
5918     HWND hwnd;
5919     HANDLE event;
5920 };
5921
5922 static DWORD WINAPI thread_proc(void *param)
5923 {
5924     MSG msg;
5925     struct wnd_event *wnd_event = (struct wnd_event *)param;
5926
5927     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
5928                                       100, 100, 200, 200, 0, 0, 0, NULL);
5929     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
5930
5931     SetEvent(wnd_event->event);
5932
5933     while (GetMessage(&msg, 0, 0, 0))
5934     {
5935         TranslateMessage(&msg);
5936         DispatchMessage(&msg);
5937     }
5938
5939     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
5940
5941     return 0;
5942 }
5943
5944 static void test_interthread_messages(void)
5945 {
5946     HANDLE hThread;
5947     DWORD tid;
5948     WNDPROC proc;
5949     MSG msg;
5950     char buf[256];
5951     int len, expected_len;
5952     struct wnd_event wnd_event;
5953     BOOL ret;
5954
5955     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
5956     if (!wnd_event.event)
5957     {
5958         trace("skipping interthread message test under win9x\n");
5959         return;
5960     }
5961
5962     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
5963     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
5964
5965     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5966
5967     CloseHandle(wnd_event.event);
5968
5969     SetLastError(0xdeadbeef);
5970     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
5971     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
5972        "wrong error code %d\n", GetLastError());
5973
5974     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5975     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
5976
5977     expected_len = lstrlenA("window caption text");
5978     memset(buf, 0, sizeof(buf));
5979     SetLastError(0xdeadbeef);
5980     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
5981     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
5982     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
5983
5984     msg.hwnd = wnd_event.hwnd;
5985     msg.message = WM_GETTEXT;
5986     msg.wParam = sizeof(buf);
5987     msg.lParam = (LPARAM)buf;
5988     memset(buf, 0, sizeof(buf));
5989     SetLastError(0xdeadbeef);
5990     len = DispatchMessageA(&msg);
5991     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
5992        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
5993
5994     /* the following test causes an exception in user.exe under win9x */
5995     msg.hwnd = wnd_event.hwnd;
5996     msg.message = WM_TIMER;
5997     msg.wParam = 0;
5998     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5999     SetLastError(0xdeadbeef);
6000     len = DispatchMessageA(&msg);
6001     ok(!len && GetLastError() == 0xdeadbeef,
6002        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6003
6004     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6005     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6006
6007     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6008     CloseHandle(hThread);
6009
6010     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6011 }
6012
6013
6014 static const struct message WmVkN[] = {
6015     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6016     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6017     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6018     { WM_CHAR, wparam|lparam, 'n', 1 },
6019     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6020     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6021     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6022     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6023     { 0 }
6024 };
6025 static const struct message WmShiftVkN[] = {
6026     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6027     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6028     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6029     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6030     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6031     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6032     { WM_CHAR, wparam|lparam, 'N', 1 },
6033     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6034     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6035     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6036     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6037     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6038     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6039     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6040     { 0 }
6041 };
6042 static const struct message WmCtrlVkN[] = {
6043     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6044     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6045     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6046     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6047     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6048     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6049     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6050     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6051     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6052     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6053     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6054     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6055     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6056     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6057     { 0 }
6058 };
6059 static const struct message WmCtrlVkN_2[] = {
6060     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6061     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6062     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6063     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6064     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6065     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6066     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6067     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6068     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6069     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6070     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6071     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6072     { 0 }
6073 };
6074 static const struct message WmAltVkN[] = {
6075     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6076     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6077     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6078     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6079     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6080     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6081     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6082     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6083     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6084     { HCBT_SYSCOMMAND, hook },
6085     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6086     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6087     { 0x00AE, sent|defwinproc|optional }, /* XP */
6088     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6089     { WM_INITMENU, sent|defwinproc },
6090     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6091     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6092     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6093     { WM_CAPTURECHANGED, sent|defwinproc },
6094     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6095     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6096     { WM_EXITMENULOOP, sent|defwinproc },
6097     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6098     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6099     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6100     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6101     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6102     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6103     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6104     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6105     { 0 }
6106 };
6107 static const struct message WmAltVkN_2[] = {
6108     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6109     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6110     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6111     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6112     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6113     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6114     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6115     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6116     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6117     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6118     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6119     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6120     { 0 }
6121 };
6122 static const struct message WmCtrlAltVkN[] = {
6123     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6124     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6125     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6126     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6127     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6128     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6129     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6130     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6131     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6132     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6133     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6134     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6135     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6136     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6137     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6138     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6139     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6140     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6141     { 0 }
6142 };
6143 static const struct message WmCtrlShiftVkN[] = {
6144     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6145     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6146     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6147     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6148     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6149     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6150     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6151     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6152     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6153     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6154     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6155     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6156     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6157     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6158     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6159     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6160     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6161     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6162     { 0 }
6163 };
6164 static const struct message WmCtrlAltShiftVkN[] = {
6165     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6166     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6167     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6168     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6169     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6170     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6171     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6172     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6173     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6174     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6175     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6176     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6177     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6178     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6179     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6180     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6181     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6182     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6183     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6184     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6185     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6186     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6187     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6188     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6189     { 0 }
6190 };
6191 static const struct message WmAltPressRelease[] = {
6192     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6193     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6194     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6195     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6196     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6197     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6198     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6199     { HCBT_SYSCOMMAND, hook },
6200     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6201     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6202     { WM_INITMENU, sent|defwinproc },
6203     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6204     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6205     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6206
6207     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6208
6209     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6210     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6211     { WM_CAPTURECHANGED, sent|defwinproc },
6212     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6213     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6214     { WM_EXITMENULOOP, sent|defwinproc },
6215     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6216     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6217     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6218     { 0 }
6219 };
6220 static const struct message WmAltMouseButton[] = {
6221     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6222     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6223     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6224     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6225     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6226     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
6227     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
6228     { WM_LBUTTONUP, wparam, 0, 0 },
6229     { WM_LBUTTONUP, sent|wparam, 0, 0 },
6230     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6231     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6232     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6233     { 0 }
6234 };
6235 static const struct message WmF1Seq[] = {
6236     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6237     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6238     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6239     { WM_KEYF1, wparam|lparam, 0, 0 },
6240     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6241     { WM_HELP, sent|defwinproc },
6242     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6243     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6244     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6245     { 0 }
6246 };
6247 static const struct message WmVkAppsSeq[] = {
6248     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6249     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6250     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6251     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6252     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6253     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6254     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6255     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6256     { 0 }
6257 };
6258
6259 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6260 {
6261     MSG msg;
6262
6263     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6264     {
6265         struct message log_msg;
6266
6267         trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
6268
6269         /* ignore some unwanted messages */
6270         if (msg.message == WM_MOUSEMOVE ||
6271             msg.message == WM_GETICON ||
6272             msg.message == WM_DEVICECHANGE)
6273             continue;
6274
6275         log_msg.message = msg.message;
6276         log_msg.flags = wparam|lparam;
6277         log_msg.wParam = msg.wParam;
6278         log_msg.lParam = msg.lParam;
6279         add_message(&log_msg);
6280
6281         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6282         {
6283             TranslateMessage(&msg);
6284             DispatchMessage(&msg);
6285         }
6286     }
6287 }
6288
6289 static void test_accelerators(void)
6290 {
6291     RECT rc;
6292     SHORT state;
6293     HACCEL hAccel;
6294     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6295                                 100, 100, 200, 200, 0, 0, 0, NULL);
6296     BOOL ret;
6297
6298     assert(hwnd != 0);
6299     UpdateWindow(hwnd);
6300     flush_events();
6301     flush_sequence();
6302
6303     SetFocus(hwnd);
6304     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6305
6306     state = GetKeyState(VK_SHIFT);
6307     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6308     state = GetKeyState(VK_CAPITAL);
6309     ok(state == 0, "wrong CapsLock state %04x\n", state);
6310
6311     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6312     assert(hAccel != 0);
6313
6314     pump_msg_loop(hwnd, 0);
6315     flush_sequence();
6316
6317     trace("testing VK_N press/release\n");
6318     flush_sequence();
6319     keybd_event('N', 0, 0, 0);
6320     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6321     pump_msg_loop(hwnd, hAccel);
6322     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6323
6324     trace("testing Shift+VK_N press/release\n");
6325     flush_sequence();
6326     keybd_event(VK_SHIFT, 0, 0, 0);
6327     keybd_event('N', 0, 0, 0);
6328     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6329     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6330     pump_msg_loop(hwnd, hAccel);
6331     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6332
6333     trace("testing Ctrl+VK_N press/release\n");
6334     flush_sequence();
6335     keybd_event(VK_CONTROL, 0, 0, 0);
6336     keybd_event('N', 0, 0, 0);
6337     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6338     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6339     pump_msg_loop(hwnd, hAccel);
6340     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6341
6342     trace("testing Alt+VK_N press/release\n");
6343     flush_sequence();
6344     keybd_event(VK_MENU, 0, 0, 0);
6345     keybd_event('N', 0, 0, 0);
6346     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6347     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6348     pump_msg_loop(hwnd, hAccel);
6349     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6350
6351     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6352     flush_sequence();
6353     keybd_event(VK_CONTROL, 0, 0, 0);
6354     keybd_event(VK_MENU, 0, 0, 0);
6355     keybd_event('N', 0, 0, 0);
6356     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6357     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6358     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6359     pump_msg_loop(hwnd, hAccel);
6360     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6361
6362     ret = DestroyAcceleratorTable(hAccel);
6363     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6364
6365     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6366     assert(hAccel != 0);
6367
6368     trace("testing VK_N press/release\n");
6369     flush_sequence();
6370     keybd_event('N', 0, 0, 0);
6371     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6372     pump_msg_loop(hwnd, hAccel);
6373     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6374
6375     trace("testing Shift+VK_N press/release\n");
6376     flush_sequence();
6377     keybd_event(VK_SHIFT, 0, 0, 0);
6378     keybd_event('N', 0, 0, 0);
6379     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6380     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6381     pump_msg_loop(hwnd, hAccel);
6382     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6383
6384     trace("testing Ctrl+VK_N press/release 2\n");
6385     flush_sequence();
6386     keybd_event(VK_CONTROL, 0, 0, 0);
6387     keybd_event('N', 0, 0, 0);
6388     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6389     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6390     pump_msg_loop(hwnd, hAccel);
6391     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6392
6393     trace("testing Alt+VK_N press/release 2\n");
6394     flush_sequence();
6395     keybd_event(VK_MENU, 0, 0, 0);
6396     keybd_event('N', 0, 0, 0);
6397     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6398     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6399     pump_msg_loop(hwnd, hAccel);
6400     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6401
6402     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6403     flush_sequence();
6404     keybd_event(VK_CONTROL, 0, 0, 0);
6405     keybd_event(VK_MENU, 0, 0, 0);
6406     keybd_event('N', 0, 0, 0);
6407     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6408     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6409     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6410     pump_msg_loop(hwnd, hAccel);
6411     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6412
6413     trace("testing Ctrl+Shift+VK_N press/release\n");
6414     flush_sequence();
6415     keybd_event(VK_CONTROL, 0, 0, 0);
6416     keybd_event(VK_SHIFT, 0, 0, 0);
6417     keybd_event('N', 0, 0, 0);
6418     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6419     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6420     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6421     pump_msg_loop(hwnd, hAccel);
6422     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6423
6424     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6425     flush_sequence();
6426     keybd_event(VK_CONTROL, 0, 0, 0);
6427     keybd_event(VK_MENU, 0, 0, 0);
6428     keybd_event(VK_SHIFT, 0, 0, 0);
6429     keybd_event('N', 0, 0, 0);
6430     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6431     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6432     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6433     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6434     pump_msg_loop(hwnd, hAccel);
6435     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6436
6437     ret = DestroyAcceleratorTable(hAccel);
6438     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6439
6440     trace("testing Alt press/release\n");
6441     flush_sequence();
6442     keybd_event(VK_MENU, 0, 0, 0);
6443     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6444     keybd_event(VK_MENU, 0, 0, 0);
6445     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6446     pump_msg_loop(hwnd, 0);
6447     /* this test doesn't pass in Wine for managed windows */
6448     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6449
6450     trace("testing Alt+MouseButton press/release\n");
6451     /* first, move mouse pointer inside of the window client area */
6452     GetClientRect(hwnd, &rc);
6453     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6454     rc.left += (rc.right - rc.left)/2;
6455     rc.top += (rc.bottom - rc.top)/2;
6456     SetCursorPos(rc.left, rc.top);
6457
6458     flush_events();
6459     flush_sequence();
6460     keybd_event(VK_MENU, 0, 0, 0);
6461     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6462     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6463     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6464     pump_msg_loop(hwnd, 0);
6465     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
6466
6467     trace("testing VK_F1 press/release\n");
6468     keybd_event(VK_F1, 0, 0, 0);
6469     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6470     pump_msg_loop(hwnd, 0);
6471     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6472
6473     trace("testing VK_APPS press/release\n");
6474     keybd_event(VK_APPS, 0, 0, 0);
6475     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6476     pump_msg_loop(hwnd, 0);
6477     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6478
6479     DestroyWindow(hwnd);
6480 }
6481
6482 /************* window procedures ********************/
6483
6484 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6485                              WPARAM wParam, LPARAM lParam)
6486 {
6487     static long defwndproc_counter = 0;
6488     static long beginpaint_counter = 0;
6489     LRESULT ret;
6490     struct message msg;
6491
6492     trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6493
6494     /* explicitly ignore WM_GETICON message */
6495     if (message == WM_GETICON) return 0;
6496
6497     switch (message)
6498     {
6499         case WM_ENABLE:
6500         {
6501             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6502             ok((BOOL)wParam == !(style & WS_DISABLED),
6503                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6504             break;
6505         }
6506
6507         case WM_CAPTURECHANGED:
6508             if (test_DestroyWindow_flag)
6509             {
6510                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6511                 if (style & WS_CHILD)
6512                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6513                 else if (style & WS_POPUP)
6514                     lParam = WND_POPUP_ID;
6515                 else
6516                     lParam = WND_PARENT_ID;
6517             }
6518             break;
6519
6520         case WM_NCDESTROY:
6521         {
6522             HWND capture;
6523
6524             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6525             capture = GetCapture();
6526             if (capture)
6527             {
6528                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6529                 trace("current capture %p, releasing...\n", capture);
6530                 ReleaseCapture();
6531             }
6532         }
6533         /* fall through */
6534         case WM_DESTROY:
6535             if (pGetAncestor)
6536                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6537             if (test_DestroyWindow_flag)
6538             {
6539                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6540                 if (style & WS_CHILD)
6541                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6542                 else if (style & WS_POPUP)
6543                     lParam = WND_POPUP_ID;
6544                 else
6545                     lParam = WND_PARENT_ID;
6546             }
6547             break;
6548
6549         /* test_accelerators() depends on this */
6550         case WM_NCHITTEST:
6551             return HTCLIENT;
6552     
6553         /* ignore */
6554         case WM_MOUSEMOVE:
6555         case WM_SETCURSOR:
6556         case WM_DEVICECHANGE:
6557             return 0;
6558
6559         case WM_WINDOWPOSCHANGING:
6560         case WM_WINDOWPOSCHANGED:
6561         {
6562             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6563
6564             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6565             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6566                   winpos->hwnd, winpos->hwndInsertAfter,
6567                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6568             dump_winpos_flags(winpos->flags);
6569
6570             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6571              * in the high word for internal purposes
6572              */
6573             wParam = winpos->flags & 0xffff;
6574             /* We are not interested in the flags that don't match under XP and Win9x */
6575             wParam &= ~(SWP_NOZORDER);
6576             break;
6577         }
6578     }
6579
6580     msg.message = message;
6581     msg.flags = sent|wparam|lparam;
6582     if (defwndproc_counter) msg.flags |= defwinproc;
6583     if (beginpaint_counter) msg.flags |= beginpaint;
6584     msg.wParam = wParam;
6585     msg.lParam = lParam;
6586     add_message(&msg);
6587
6588     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6589     {
6590         HWND parent = GetParent(hwnd);
6591         RECT rc;
6592         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6593
6594         GetClientRect(parent, &rc);
6595         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6596         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
6597               minmax->ptReserved.x, minmax->ptReserved.y,
6598               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6599               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6600               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6601               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6602
6603         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6604            minmax->ptMaxSize.x, rc.right);
6605         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6606            minmax->ptMaxSize.y, rc.bottom);
6607     }
6608
6609     if (message == WM_PAINT)
6610     {
6611         PAINTSTRUCT ps;
6612         beginpaint_counter++;
6613         BeginPaint( hwnd, &ps );
6614         beginpaint_counter--;
6615         EndPaint( hwnd, &ps );
6616         return 0;
6617     }
6618
6619     defwndproc_counter++;
6620     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
6621                   : DefWindowProcA(hwnd, message, wParam, lParam);
6622     defwndproc_counter--;
6623
6624     return ret;
6625 }
6626
6627 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6628 {
6629     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6630 }
6631
6632 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6633 {
6634     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6635 }
6636
6637 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6638 {
6639     static long defwndproc_counter = 0;
6640     LRESULT ret;
6641     struct message msg;
6642
6643     trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6644
6645     /* explicitly ignore WM_GETICON message */
6646     if (message == WM_GETICON) return 0;
6647
6648     msg.message = message;
6649     msg.flags = sent|wparam|lparam;
6650     if (defwndproc_counter) msg.flags |= defwinproc;
6651     msg.wParam = wParam;
6652     msg.lParam = lParam;
6653     add_message(&msg);
6654
6655     if (message == WM_CREATE)
6656     {
6657         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6658         SetWindowLongA(hwnd, GWL_STYLE, style);
6659     }
6660
6661     defwndproc_counter++;
6662     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6663     defwndproc_counter--;
6664
6665     return ret;
6666 }
6667
6668 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6669 {
6670     static long defwndproc_counter = 0;
6671     static long beginpaint_counter = 0;
6672     LRESULT ret;
6673     struct message msg;
6674     LPARAM logged_lParam;
6675
6676     trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6677
6678     /* explicitly ignore WM_GETICON message */
6679     if (message == WM_GETICON) return 0;
6680
6681     logged_lParam=lParam;
6682     if (log_all_parent_messages ||
6683         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6684         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6685         message == WM_ENABLE || message == WM_ENTERIDLE ||
6686         message == WM_DRAWITEM ||
6687         message == WM_IME_SETCONTEXT)
6688     {
6689         switch (message)
6690         {
6691             /* ignore */
6692             case WM_NCHITTEST:
6693                 return HTCLIENT;
6694             case WM_SETCURSOR:
6695             case WM_MOUSEMOVE:
6696                 return 0;
6697
6698             case WM_ERASEBKGND:
6699             {
6700                 RECT rc;
6701                 INT ret = GetClipBox((HDC)wParam, &rc);
6702
6703                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6704                        ret, rc.left, rc.top, rc.right, rc.bottom);
6705                 break;
6706             }
6707
6708             case WM_WINDOWPOSCHANGING:
6709             case WM_WINDOWPOSCHANGED:
6710             {
6711                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6712
6713                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6714                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6715                       winpos->hwnd, winpos->hwndInsertAfter,
6716                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6717                 dump_winpos_flags(winpos->flags);
6718
6719                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6720                  * in the high word for internal purposes
6721                  */
6722                 wParam = winpos->flags & 0xffff;
6723                 /* We are not interested in the flags that don't match under XP and Win9x */
6724                 wParam &= ~(SWP_NOZORDER);
6725                 break;
6726             }
6727
6728             case WM_DRAWITEM:
6729             {
6730                 /* encode DRAWITEMSTRUCT into an LPARAM */
6731                 DRAW_ITEM_STRUCT di;
6732                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
6733
6734                 trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n",
6735                       dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState);
6736
6737                 di.u.item.type = dis->CtlType;
6738                 di.u.item.ctl_id = dis->CtlID;
6739                 di.u.item.item_id = dis->itemID;
6740                 di.u.item.action = dis->itemAction;
6741                 di.u.item.state = dis->itemState;
6742
6743                 logged_lParam = di.u.lp;
6744                 break;
6745             }
6746         }
6747
6748         msg.message = message;
6749         msg.flags = sent|parent|wparam|lparam;
6750         if (defwndproc_counter) msg.flags |= defwinproc;
6751         if (beginpaint_counter) msg.flags |= beginpaint;
6752         msg.wParam = wParam;
6753         msg.lParam = logged_lParam;
6754         add_message(&msg);
6755     }
6756
6757     if (message == WM_PAINT)
6758     {
6759         PAINTSTRUCT ps;
6760         beginpaint_counter++;
6761         BeginPaint( hwnd, &ps );
6762         beginpaint_counter--;
6763         EndPaint( hwnd, &ps );
6764         return 0;
6765     }
6766
6767     defwndproc_counter++;
6768     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6769     defwndproc_counter--;
6770
6771     return ret;
6772 }
6773
6774 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6775 {
6776     static long defwndproc_counter = 0;
6777     LRESULT ret;
6778     struct message msg;
6779
6780     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6781
6782     /* explicitly ignore WM_GETICON message */
6783     if (message == WM_GETICON) return 0;
6784
6785     if (test_def_id)
6786     {
6787         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6788         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6789         if (after_end_dialog)
6790             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6791         else
6792             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6793     }
6794
6795     switch (message)
6796     {
6797         case WM_WINDOWPOSCHANGING:
6798         case WM_WINDOWPOSCHANGED:
6799         {
6800             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6801
6802             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6803             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6804                   winpos->hwnd, winpos->hwndInsertAfter,
6805                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6806             dump_winpos_flags(winpos->flags);
6807
6808             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6809              * in the high word for internal purposes
6810              */
6811             wParam = winpos->flags & 0xffff;
6812             /* We are not interested in the flags that don't match under XP and Win9x */
6813             wParam &= ~(SWP_NOZORDER);
6814             break;
6815         }
6816     }
6817
6818     msg.message = message;
6819     msg.flags = sent|wparam|lparam;
6820     if (defwndproc_counter) msg.flags |= defwinproc;
6821     msg.wParam = wParam;
6822     msg.lParam = lParam;
6823     add_message(&msg);
6824
6825     defwndproc_counter++;
6826     ret = DefDlgProcA(hwnd, message, wParam, lParam);
6827     defwndproc_counter--;
6828
6829     return ret;
6830 }
6831
6832 static void dump_winpos_flags(UINT flags)
6833 {
6834     if (!winetest_debug) return;
6835
6836     if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6837     if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6838     if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6839     if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6840     if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6841     if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6842     if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6843     if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6844     if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6845     if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6846     if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6847     if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6848     if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6849     if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
6850     if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
6851
6852 #define DUMPED_FLAGS \
6853     (SWP_NOSIZE | \
6854     SWP_NOMOVE | \
6855     SWP_NOZORDER | \
6856     SWP_NOREDRAW | \
6857     SWP_NOACTIVATE | \
6858     SWP_FRAMECHANGED | \
6859     SWP_SHOWWINDOW | \
6860     SWP_HIDEWINDOW | \
6861     SWP_NOCOPYBITS | \
6862     SWP_NOOWNERZORDER | \
6863     SWP_NOSENDCHANGING | \
6864     SWP_DEFERERASE | \
6865     SWP_ASYNCWINDOWPOS | \
6866     SWP_NOCLIENTSIZE | \
6867     SWP_NOCLIENTMOVE)
6868
6869     if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
6870     printf("\n");
6871 #undef DUMPED_FLAGS
6872 }
6873
6874 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6875 {
6876     static long defwndproc_counter = 0;
6877     LRESULT ret;
6878     struct message msg;
6879
6880     /* log only specific messages we are interested in */
6881     switch (message)
6882     {
6883 #if 0 /* probably log these as well */
6884     case WM_ACTIVATE:
6885     case WM_SETFOCUS:
6886     case WM_KILLFOCUS:
6887 #endif
6888     case WM_SHOWWINDOW:
6889         trace("WM_SHOWWINDOW %ld\n", wParam);
6890         break;
6891     case WM_SIZE:
6892         trace("WM_SIZE %ld\n", wParam);
6893         break;
6894     case WM_MOVE:
6895         trace("WM_MOVE\n");
6896         break;
6897     case WM_GETMINMAXINFO:
6898         trace("WM_GETMINMAXINFO\n");
6899         break;
6900
6901     case WM_WINDOWPOSCHANGING:
6902     case WM_WINDOWPOSCHANGED:
6903     {
6904         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6905
6906         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6907         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6908               winpos->hwnd, winpos->hwndInsertAfter,
6909               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6910         trace("flags: ");
6911         dump_winpos_flags(winpos->flags);
6912
6913         /* Log only documented flags, win2k uses 0x1000 and 0x2000
6914          * in the high word for internal purposes
6915          */
6916         wParam = winpos->flags & 0xffff;
6917         /* We are not interested in the flags that don't match under XP and Win9x */
6918         wParam &= ~(SWP_NOZORDER);
6919         break;
6920     }
6921
6922     default: /* ignore */
6923         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
6924         return DefWindowProcA(hwnd, message, wParam, lParam);
6925     }
6926
6927     msg.message = message;
6928     msg.flags = sent|wparam|lparam;
6929     if (defwndproc_counter) msg.flags |= defwinproc;
6930     msg.wParam = wParam;
6931     msg.lParam = lParam;
6932     add_message(&msg);
6933
6934     defwndproc_counter++;
6935     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6936     defwndproc_counter--;
6937
6938     return ret;
6939 }
6940
6941 static BOOL RegisterWindowClasses(void)
6942 {
6943     WNDCLASSA cls;
6944     WNDCLASSW clsW;
6945
6946     cls.style = 0;
6947     cls.lpfnWndProc = MsgCheckProcA;
6948     cls.cbClsExtra = 0;
6949     cls.cbWndExtra = 0;
6950     cls.hInstance = GetModuleHandleA(0);
6951     cls.hIcon = 0;
6952     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
6953     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6954     cls.lpszMenuName = NULL;
6955     cls.lpszClassName = "TestWindowClass";
6956     if(!RegisterClassA(&cls)) return FALSE;
6957
6958     cls.lpfnWndProc = ShowWindowProcA;
6959     cls.lpszClassName = "ShowWindowClass";
6960     if(!RegisterClassA(&cls)) return FALSE;
6961
6962     cls.lpfnWndProc = PopupMsgCheckProcA;
6963     cls.lpszClassName = "TestPopupClass";
6964     if(!RegisterClassA(&cls)) return FALSE;
6965
6966     cls.lpfnWndProc = ParentMsgCheckProcA;
6967     cls.lpszClassName = "TestParentClass";
6968     if(!RegisterClassA(&cls)) return FALSE;
6969
6970     cls.lpfnWndProc = DefWindowProcA;
6971     cls.lpszClassName = "SimpleWindowClass";
6972     if(!RegisterClassA(&cls)) return FALSE;
6973
6974     cls.style = CS_NOCLOSE;
6975     cls.lpszClassName = "NoCloseWindowClass";
6976     if(!RegisterClassA(&cls)) return FALSE;
6977
6978     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
6979     cls.style = 0;
6980     cls.hInstance = GetModuleHandleA(0);
6981     cls.hbrBackground = 0;
6982     cls.lpfnWndProc = TestDlgProcA;
6983     cls.lpszClassName = "TestDialogClass";
6984     if(!RegisterClassA(&cls)) return FALSE;
6985
6986     clsW.style = 0;
6987     clsW.lpfnWndProc = MsgCheckProcW;
6988     clsW.cbClsExtra = 0;
6989     clsW.cbWndExtra = 0;
6990     clsW.hInstance = GetModuleHandleW(0);
6991     clsW.hIcon = 0;
6992     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6993     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
6994     clsW.lpszMenuName = NULL;
6995     clsW.lpszClassName = testWindowClassW;
6996     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
6997
6998     return TRUE;
6999 }
7000
7001 static BOOL is_our_logged_class(HWND hwnd)
7002 {
7003     char buf[256];
7004
7005     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7006     {
7007         if (!lstrcmpiA(buf, "TestWindowClass") ||
7008             !lstrcmpiA(buf, "ShowWindowClass") ||
7009             !lstrcmpiA(buf, "TestParentClass") ||
7010             !lstrcmpiA(buf, "TestPopupClass") ||
7011             !lstrcmpiA(buf, "SimpleWindowClass") ||
7012             !lstrcmpiA(buf, "TestDialogClass") ||
7013             !lstrcmpiA(buf, "MDI_frame_class") ||
7014             !lstrcmpiA(buf, "MDI_client_class") ||
7015             !lstrcmpiA(buf, "MDI_child_class") ||
7016             !lstrcmpiA(buf, "my_button_class") ||
7017             !lstrcmpiA(buf, "my_edit_class") ||
7018             !lstrcmpiA(buf, "static") ||
7019             !lstrcmpiA(buf, "ListBox") ||
7020             !lstrcmpiA(buf, "ComboBox") ||
7021             !lstrcmpiA(buf, "MyDialogClass") ||
7022             !lstrcmpiA(buf, "#32770") ||
7023             !lstrcmpiA(buf, "#32768"))
7024         return TRUE;
7025         trace("ignoring window class %s\n", buf);
7026     }
7027     return FALSE;
7028 }
7029
7030 static HHOOK hCBT_hook;
7031 static DWORD cbt_hook_thread_id;
7032
7033 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7034
7035     static const char * const CBT_code_name[10] = {
7036         "HCBT_MOVESIZE",
7037         "HCBT_MINMAX",
7038         "HCBT_QS",
7039         "HCBT_CREATEWND",
7040         "HCBT_DESTROYWND",
7041         "HCBT_ACTIVATE",
7042         "HCBT_CLICKSKIPPED",
7043         "HCBT_KEYSKIPPED",
7044         "HCBT_SYSCOMMAND",
7045         "HCBT_SETFOCUS" };
7046     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
7047     HWND hwnd;
7048
7049     trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
7050
7051     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7052
7053     if (nCode == HCBT_CLICKSKIPPED)
7054     {
7055         /* ignore this event, XP sends it a lot when switching focus between windows */
7056         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7057     }
7058
7059     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7060     {
7061         struct message msg;
7062
7063         msg.message = nCode;
7064         msg.flags = hook|wparam|lparam;
7065         msg.wParam = wParam;
7066         msg.lParam = lParam;
7067         add_message(&msg);
7068
7069         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7070     }
7071
7072     if (nCode == HCBT_DESTROYWND)
7073     {
7074         if (test_DestroyWindow_flag)
7075         {
7076             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7077             if (style & WS_CHILD)
7078                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7079             else if (style & WS_POPUP)
7080                 lParam = WND_POPUP_ID;
7081             else
7082                 lParam = WND_PARENT_ID;
7083         }
7084     }
7085
7086     /* Log also SetFocus(0) calls */
7087     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7088
7089     if (is_our_logged_class(hwnd))
7090     {
7091         struct message msg;
7092
7093         msg.message = nCode;
7094         msg.flags = hook|wparam|lparam;
7095         msg.wParam = wParam;
7096         msg.lParam = lParam;
7097         add_message(&msg);
7098     }
7099     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7100 }
7101
7102 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7103                                     DWORD event,
7104                                     HWND hwnd,
7105                                     LONG object_id,
7106                                     LONG child_id,
7107                                     DWORD thread_id,
7108                                     DWORD event_time)
7109 {
7110     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7111            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7112
7113     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7114
7115     /* ignore mouse cursor events */
7116     if (object_id == OBJID_CURSOR) return;
7117
7118     if (!hwnd || is_our_logged_class(hwnd))
7119     {
7120         struct message msg;
7121
7122         msg.message = event;
7123         msg.flags = winevent_hook|wparam|lparam;
7124         msg.wParam = object_id;
7125         msg.lParam = child_id;
7126         add_message(&msg);
7127     }
7128 }
7129
7130 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7131 static const WCHAR wszAnsi[] = {'U',0};
7132
7133 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7134 {
7135     switch (uMsg)
7136     {
7137     case CB_FINDSTRINGEXACT:
7138         trace("String: %p\n", (LPCWSTR)lParam);
7139         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7140             return 1;
7141         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7142             return 0;
7143         return -1;
7144     }
7145     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7146 }
7147
7148 static const struct message WmGetTextLengthAfromW[] = {
7149     { WM_GETTEXTLENGTH, sent },
7150     { WM_GETTEXT, sent },
7151     { 0 }
7152 };
7153
7154 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7155
7156 /* dummy window proc for WM_GETTEXTLENGTH test */
7157 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7158 {
7159     switch(msg)
7160     {
7161     case WM_GETTEXTLENGTH:
7162         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7163     case WM_GETTEXT:
7164         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7165         return lstrlenW( (LPWSTR)lp );
7166     default:
7167         return DefWindowProcW( hwnd, msg, wp, lp );
7168     }
7169 }
7170
7171 static void test_message_conversion(void)
7172 {
7173     static const WCHAR wszMsgConversionClass[] =
7174         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7175     WNDCLASSW cls;
7176     LRESULT lRes;
7177     HWND hwnd;
7178     WNDPROC wndproc, newproc;
7179     BOOL ret;
7180
7181     cls.style = 0;
7182     cls.lpfnWndProc = MsgConversionProcW;
7183     cls.cbClsExtra = 0;
7184     cls.cbWndExtra = 0;
7185     cls.hInstance = GetModuleHandleW(NULL);
7186     cls.hIcon = NULL;
7187     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7188     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7189     cls.lpszMenuName = NULL;
7190     cls.lpszClassName = wszMsgConversionClass;
7191     /* this call will fail on Win9x, but that doesn't matter as this test is
7192      * meaningless on those platforms */
7193     if(!RegisterClassW(&cls)) return;
7194
7195     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7196                            100, 100, 200, 200, 0, 0, 0, NULL);
7197     ok(hwnd != NULL, "Window creation failed\n");
7198
7199     /* {W, A} -> A */
7200
7201     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7202     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7203     ok(lRes == 0, "String should have been converted\n");
7204     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7205     ok(lRes == 1, "String shouldn't have been converted\n");
7206
7207     /* {W, A} -> W */
7208
7209     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7210     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7211     ok(lRes == 1, "String shouldn't have been converted\n");
7212     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7213     ok(lRes == 1, "String shouldn't have been converted\n");
7214
7215     /* Synchronous messages */
7216
7217     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7218     ok(lRes == 0, "String should have been converted\n");
7219     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7220     ok(lRes == 1, "String shouldn't have been converted\n");
7221
7222     /* Asynchronous messages */
7223
7224     SetLastError(0);
7225     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7226     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7227         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7228     SetLastError(0);
7229     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7230     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7231         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7232     SetLastError(0);
7233     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7234     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7235         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7236     SetLastError(0);
7237     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7238     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7239         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7240     SetLastError(0);
7241     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7242     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7243         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7244     SetLastError(0);
7245     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7246     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7247         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7248     SetLastError(0);
7249     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7250     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7251         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7252     SetLastError(0);
7253     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7254     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7255         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7256
7257     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7258
7259     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7260                           WS_OVERLAPPEDWINDOW,
7261                           100, 100, 200, 200, 0, 0, 0, NULL);
7262     assert(hwnd);
7263     flush_sequence();
7264     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7265     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7266     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7267         "got bad length %ld\n", lRes );
7268
7269     flush_sequence();
7270     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7271                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7272     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7273     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7274         "got bad length %ld\n", lRes );
7275
7276     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7277     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7278     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7279     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7280                                      NULL, 0, NULL, NULL ),
7281         "got bad length %ld\n", lRes );
7282
7283     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7284     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7285     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7286                                      NULL, 0, NULL, NULL ),
7287         "got bad length %ld\n", lRes );
7288
7289     ret = DestroyWindow(hwnd);
7290     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7291 }
7292
7293 struct timer_info
7294 {
7295     HWND hWnd;
7296     HANDLE handles[2];
7297     DWORD id;
7298 };
7299
7300 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7301 {
7302 }
7303
7304 #define TIMER_ID  0x19
7305
7306 static DWORD WINAPI timer_thread_proc(LPVOID x)
7307 {
7308     struct timer_info *info = x;
7309     DWORD r;
7310
7311     r = KillTimer(info->hWnd, 0x19);
7312     ok(r,"KillTimer failed in thread\n");
7313     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7314     ok(r,"SetTimer failed in thread\n");
7315     ok(r==TIMER_ID,"SetTimer id different\n");
7316     r = SetEvent(info->handles[0]);
7317     ok(r,"SetEvent failed in thread\n");
7318     return 0;
7319 }
7320
7321 static void test_timers(void)
7322 {
7323     struct timer_info info;
7324     DWORD id;
7325
7326     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7327        WS_OVERLAPPEDWINDOW ,
7328        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7329        NULL, NULL, 0);
7330
7331     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7332     ok(info.id, "SetTimer failed\n");
7333     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7334     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7335     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7336
7337     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7338
7339     WaitForSingleObject(info.handles[1], INFINITE);
7340
7341     CloseHandle(info.handles[0]);
7342     CloseHandle(info.handles[1]);
7343
7344     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7345
7346     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7347 }
7348
7349 static int count = 0;
7350 static VOID CALLBACK callback_count(
7351     HWND hwnd,
7352     UINT uMsg,
7353     UINT_PTR idEvent,
7354     DWORD dwTime
7355 )
7356 {
7357     count++;
7358 }
7359
7360 static void test_timers_no_wnd(void)
7361 {
7362     UINT_PTR id, id2;
7363     MSG msg;
7364
7365     count = 0;
7366     id = SetTimer(NULL, 0, 100, callback_count);
7367     ok(id != 0, "did not get id from SetTimer.\n");
7368     id2 = SetTimer(NULL, id, 200, callback_count);
7369     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7370     Sleep(150);
7371     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7372     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7373     Sleep(150);
7374     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7375     ok(count == 1, "did not get one count as expected (%i).\n", count);
7376     KillTimer(NULL, id);
7377     Sleep(250);
7378     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7379     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7380 }
7381
7382 /* Various win events with arbitrary parameters */
7383 static const struct message WmWinEventsSeq[] = {
7384     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7385     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7386     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7387     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7388     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7389     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7390     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7391     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7392     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7393     /* our win event hook ignores OBJID_CURSOR events */
7394     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7395     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7396     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7397     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7398     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7399     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7400     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7401     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7402     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7403     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7404     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7405     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7406     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7407     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7408     { 0 }
7409 };
7410 static const struct message WmWinEventCaretSeq[] = {
7411     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7412     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7413     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7414     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7415     { 0 }
7416 };
7417 static const struct message WmWinEventCaretSeq_2[] = {
7418     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7419     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7420     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7421     { 0 }
7422 };
7423 static const struct message WmWinEventAlertSeq[] = {
7424     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7425     { 0 }
7426 };
7427 static const struct message WmWinEventAlertSeq_2[] = {
7428     /* create window in the thread proc */
7429     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7430     /* our test event */
7431     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7432     { 0 }
7433 };
7434 static const struct message WmGlobalHookSeq_1[] = {
7435     /* create window in the thread proc */
7436     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7437     /* our test events */
7438     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7439     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7440     { 0 }
7441 };
7442 static const struct message WmGlobalHookSeq_2[] = {
7443     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7444     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7445     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7446     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7447     { 0 }
7448 };
7449
7450 static const struct message WmMouseLLHookSeq[] = {
7451     { WM_MOUSEMOVE, hook },
7452     { WM_LBUTTONUP, hook },
7453     { WM_MOUSEMOVE, hook },
7454     { 0 }
7455 };
7456
7457 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7458                                          DWORD event,
7459                                          HWND hwnd,
7460                                          LONG object_id,
7461                                          LONG child_id,
7462                                          DWORD thread_id,
7463                                          DWORD event_time)
7464 {
7465     char buf[256];
7466
7467     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7468            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7469
7470     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7471     {
7472         if (!lstrcmpiA(buf, "TestWindowClass") ||
7473             !lstrcmpiA(buf, "static"))
7474         {
7475             struct message msg;
7476
7477             msg.message = event;
7478             msg.flags = winevent_hook|wparam|lparam;
7479             msg.wParam = object_id;
7480             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7481             add_message(&msg);
7482         }
7483     }
7484 }
7485
7486 static HHOOK hCBT_global_hook;
7487 static DWORD cbt_global_hook_thread_id;
7488
7489 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7490
7491     HWND hwnd;
7492     char buf[256];
7493
7494     trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
7495
7496     if (nCode == HCBT_SYSCOMMAND)
7497     {
7498         struct message msg;
7499
7500         msg.message = nCode;
7501         msg.flags = hook|wparam|lparam;
7502         msg.wParam = wParam;
7503         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7504         add_message(&msg);
7505
7506         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7507     }
7508     /* WH_MOUSE_LL hook */
7509     if (nCode == HC_ACTION)
7510     {
7511         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7512
7513         /* we can't test for real mouse events */
7514         if (mhll->flags & LLMHF_INJECTED)
7515         {
7516             struct message msg;
7517
7518             memset (&msg, 0, sizeof (msg));
7519             msg.message = wParam;
7520             msg.flags = hook;
7521             add_message(&msg);
7522         }
7523         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7524     }
7525
7526     /* Log also SetFocus(0) calls */
7527     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7528
7529     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7530     {
7531         if (!lstrcmpiA(buf, "TestWindowClass") ||
7532             !lstrcmpiA(buf, "static"))
7533         {
7534             struct message msg;
7535
7536             msg.message = nCode;
7537             msg.flags = hook|wparam|lparam;
7538             msg.wParam = wParam;
7539             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7540             add_message(&msg);
7541         }
7542     }
7543     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7544 }
7545
7546 static DWORD WINAPI win_event_global_thread_proc(void *param)
7547 {
7548     HWND hwnd;
7549     MSG msg;
7550     HANDLE hevent = *(HANDLE *)param;
7551
7552     assert(pNotifyWinEvent);
7553
7554     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7555     assert(hwnd);
7556     trace("created thread window %p\n", hwnd);
7557
7558     *(HWND *)param = hwnd;
7559
7560     flush_sequence();
7561     /* this event should be received only by our new hook proc,
7562      * an old one does not expect an event from another thread.
7563      */
7564     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7565     SetEvent(hevent);
7566
7567     while (GetMessage(&msg, 0, 0, 0))
7568     {
7569         TranslateMessage(&msg);
7570         DispatchMessage(&msg);
7571     }
7572     return 0;
7573 }
7574
7575 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7576 {
7577     HWND hwnd;
7578     MSG msg;
7579     HANDLE hevent = *(HANDLE *)param;
7580
7581     flush_sequence();
7582     /* these events should be received only by our new hook proc,
7583      * an old one does not expect an event from another thread.
7584      */
7585
7586     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7587     assert(hwnd);
7588     trace("created thread window %p\n", hwnd);
7589
7590     *(HWND *)param = hwnd;
7591
7592     /* Windows doesn't like when a thread plays games with the focus,
7593        that leads to all kinds of misbehaviours and failures to activate
7594        a window. So, better keep next lines commented out.
7595     SetFocus(0);
7596     SetFocus(hwnd);*/
7597
7598     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7599     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7600
7601     SetEvent(hevent);
7602
7603     while (GetMessage(&msg, 0, 0, 0))
7604     {
7605         TranslateMessage(&msg);
7606         DispatchMessage(&msg);
7607     }
7608     return 0;
7609 }
7610
7611 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7612 {
7613     HWND hwnd;
7614     MSG msg;
7615     HANDLE hevent = *(HANDLE *)param;
7616
7617     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7618     assert(hwnd);
7619     trace("created thread window %p\n", hwnd);
7620
7621     *(HWND *)param = hwnd;
7622
7623     flush_sequence();
7624
7625     /* Windows doesn't like when a thread plays games with the focus,
7626      * that leads to all kinds of misbehaviours and failures to activate
7627      * a window. So, better don't generate a mouse click message below.
7628      */
7629     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7630     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7631     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7632
7633     SetEvent(hevent);
7634     while (GetMessage(&msg, 0, 0, 0))
7635     {
7636         TranslateMessage(&msg);
7637         DispatchMessage(&msg);
7638     }
7639     return 0;
7640 }
7641
7642 static void test_winevents(void)
7643 {
7644     BOOL ret;
7645     MSG msg;
7646     HWND hwnd, hwnd2;
7647     UINT i;
7648     HANDLE hthread, hevent;
7649     DWORD tid;
7650     HWINEVENTHOOK hhook;
7651     const struct message *events = WmWinEventsSeq;
7652
7653     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7654                            WS_OVERLAPPEDWINDOW,
7655                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7656                            NULL, NULL, 0);
7657     assert(hwnd);
7658
7659     /****** start of global hook test *************/
7660     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7661     if (!hCBT_global_hook)
7662     {
7663         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7664         skip( "cannot set global hook\n" );
7665         return;
7666     }
7667
7668     hevent = CreateEventA(NULL, 0, 0, NULL);
7669     assert(hevent);
7670     hwnd2 = (HWND)hevent;
7671
7672     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7673     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7674
7675     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7676
7677     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7678
7679     flush_sequence();
7680     /* this one should be received only by old hook proc */
7681     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7682     /* this one should be received only by old hook proc */
7683     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7684
7685     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7686
7687     ret = UnhookWindowsHookEx(hCBT_global_hook);
7688     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7689
7690     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7691     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7692     CloseHandle(hthread);
7693     CloseHandle(hevent);
7694     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7695     /****** end of global hook test *************/
7696
7697     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7698     {
7699         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7700         return;
7701     }
7702
7703     flush_sequence();
7704
7705     if (0)
7706     {
7707     /* this test doesn't pass under Win9x */
7708     /* win2k ignores events with hwnd == 0 */
7709     SetLastError(0xdeadbeef);
7710     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7711     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7712        GetLastError() == 0xdeadbeef, /* Win9x */
7713        "unexpected error %d\n", GetLastError());
7714     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7715     }
7716
7717     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7718         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7719
7720     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7721
7722     /****** start of event filtering test *************/
7723     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7724         EVENT_OBJECT_SHOW, /* 0x8002 */
7725         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7726         GetModuleHandleA(0), win_event_global_hook_proc,
7727         GetCurrentProcessId(), 0,
7728         WINEVENT_INCONTEXT);
7729     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7730
7731     hevent = CreateEventA(NULL, 0, 0, NULL);
7732     assert(hevent);
7733     hwnd2 = (HWND)hevent;
7734
7735     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7736     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7737
7738     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7739
7740     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7741
7742     flush_sequence();
7743     /* this one should be received only by old hook proc */
7744     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7745     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7746     /* this one should be received only by old hook proc */
7747     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7748
7749     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7750
7751     ret = pUnhookWinEvent(hhook);
7752     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7753
7754     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7755     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7756     CloseHandle(hthread);
7757     CloseHandle(hevent);
7758     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7759     /****** end of event filtering test *************/
7760
7761     /****** start of out of context event test *************/
7762     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7763         EVENT_MIN, EVENT_MAX,
7764         0, win_event_global_hook_proc,
7765         GetCurrentProcessId(), 0,
7766         WINEVENT_OUTOFCONTEXT);
7767     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7768
7769     hevent = CreateEventA(NULL, 0, 0, NULL);
7770     assert(hevent);
7771     hwnd2 = (HWND)hevent;
7772
7773     flush_sequence();
7774
7775     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7776     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7777
7778     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7779
7780     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7781     /* process pending winevent messages */
7782     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7783     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7784
7785     flush_sequence();
7786     /* this one should be received only by old hook proc */
7787     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7788     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7789     /* this one should be received only by old hook proc */
7790     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7791
7792     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7793     /* process pending winevent messages */
7794     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7795     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7796
7797     ret = pUnhookWinEvent(hhook);
7798     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7799
7800     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7801     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7802     CloseHandle(hthread);
7803     CloseHandle(hevent);
7804     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7805     /****** end of out of context event test *************/
7806
7807     /****** start of MOUSE_LL hook test *************/
7808     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7809     /* WH_MOUSE_LL is not supported on Win9x platforms */
7810     if (!hCBT_global_hook)
7811     {
7812         trace("Skipping WH_MOUSE_LL test on this platform\n");
7813         goto skip_mouse_ll_hook_test;
7814     }
7815
7816     hevent = CreateEventA(NULL, 0, 0, NULL);
7817     assert(hevent);
7818     hwnd2 = (HWND)hevent;
7819
7820     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7821     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7822
7823     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7824         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7825
7826     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7827     flush_sequence();
7828
7829     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7830     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7831     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7832
7833     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7834
7835     ret = UnhookWindowsHookEx(hCBT_global_hook);
7836     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7837
7838     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7839     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7840     CloseHandle(hthread);
7841     CloseHandle(hevent);
7842     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7843     /****** end of MOUSE_LL hook test *************/
7844 skip_mouse_ll_hook_test:
7845
7846     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7847 }
7848
7849 static void test_set_hook(void)
7850 {
7851     BOOL ret;
7852     HHOOK hhook;
7853     HWINEVENTHOOK hwinevent_hook;
7854
7855     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7856     ok(hhook != 0, "local hook does not require hModule set to 0\n");
7857     UnhookWindowsHookEx(hhook);
7858
7859     if (0)
7860     {
7861     /* this test doesn't pass under Win9x: BUG! */
7862     SetLastError(0xdeadbeef);
7863     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7864     ok(!hhook, "global hook requires hModule != 0\n");
7865     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7866     }
7867
7868     SetLastError(0xdeadbeef);
7869     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7870     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7871     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7872        GetLastError() == 0xdeadbeef, /* Win9x */
7873        "unexpected error %d\n", GetLastError());
7874
7875     SetLastError(0xdeadbeef);
7876     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7877     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7878        GetLastError() == 0xdeadbeef, /* Win9x */
7879        "unexpected error %d\n", GetLastError());
7880
7881     if (!pSetWinEventHook || !pUnhookWinEvent) return;
7882
7883     /* even process local incontext hooks require hmodule */
7884     SetLastError(0xdeadbeef);
7885     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7886         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7887     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7888     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7889        GetLastError() == 0xdeadbeef, /* Win9x */
7890        "unexpected error %d\n", GetLastError());
7891
7892     /* even thread local incontext hooks require hmodule */
7893     SetLastError(0xdeadbeef);
7894     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7895         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7896     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7897     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7898        GetLastError() == 0xdeadbeef, /* Win9x */
7899        "unexpected error %d\n", GetLastError());
7900
7901     if (0)
7902     {
7903     /* these 3 tests don't pass under Win9x */
7904     SetLastError(0xdeadbeef);
7905     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7906         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7907     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7908     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7909
7910     SetLastError(0xdeadbeef);
7911     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7912         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7913     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7914     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7915
7916     SetLastError(0xdeadbeef);
7917     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7918         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7919     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7920     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7921     }
7922
7923     SetLastError(0xdeadbeef);
7924     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7925         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7926     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7927     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7928     ret = pUnhookWinEvent(hwinevent_hook);
7929     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7930
7931 todo_wine {
7932     /* This call succeeds under win2k SP4, but fails under Wine.
7933        Does win2k test/use passed process id? */
7934     SetLastError(0xdeadbeef);
7935     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7936         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7937     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7938     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7939     ret = pUnhookWinEvent(hwinevent_hook);
7940     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7941 }
7942
7943     SetLastError(0xdeadbeef);
7944     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7945     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7946         GetLastError() == 0xdeadbeef, /* Win9x */
7947         "unexpected error %d\n", GetLastError());
7948 }
7949
7950 static const struct message ScrollWindowPaint1[] = {
7951     { WM_PAINT, sent },
7952     { WM_ERASEBKGND, sent|beginpaint },
7953     { 0 }
7954 };
7955
7956 static const struct message ScrollWindowPaint2[] = {
7957     { WM_PAINT, sent },
7958     { 0 }
7959 };
7960
7961 static void test_scrollwindowex(void)
7962 {
7963     HWND hwnd, hchild;
7964     RECT rect={0,0,130,130};
7965
7966     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7967             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7968             100, 100, 200, 200, 0, 0, 0, NULL);
7969     ok (hwnd != 0, "Failed to create overlapped window\n");
7970     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
7971             WS_VISIBLE|WS_CAPTION|WS_CHILD,
7972             10, 10, 150, 150, hwnd, 0, 0, NULL);
7973     ok (hchild != 0, "Failed to create child\n");
7974     UpdateWindow(hwnd);
7975     flush_events();
7976     flush_sequence();
7977
7978     /* scroll without the child window */
7979     trace("start scroll\n");
7980     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7981             SW_ERASE|SW_INVALIDATE);
7982     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7983     trace("end scroll\n");
7984     flush_sequence();
7985     flush_events();
7986     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7987     flush_events();
7988     flush_sequence();
7989
7990     /* Now without the SW_ERASE flag */
7991     trace("start scroll\n");
7992     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7993     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7994     trace("end scroll\n");
7995     flush_sequence();
7996     flush_events();
7997     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7998     flush_events();
7999     flush_sequence();
8000
8001     /* now scroll the child window as well */
8002     trace("start scroll\n");
8003     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8004             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8005     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8006                 /* windows sometimes a WM_MOVE */
8007         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8008     }
8009     trace("end scroll\n");
8010     flush_sequence();
8011     flush_events();
8012     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8013     flush_events();
8014     flush_sequence();
8015
8016     /* now scroll with ScrollWindow() */
8017     trace("start scroll with ScrollWindow\n");
8018     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8019     trace("end scroll\n");
8020     flush_sequence();
8021     flush_events();
8022     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8023
8024     ok(DestroyWindow(hchild), "failed to destroy window\n");
8025     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8026     flush_sequence();
8027 }
8028
8029 static const struct message destroy_window_with_children[] = {
8030     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8031     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8032     { 0x0090, sent|optional },
8033     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8034     { 0x0090, sent|optional },
8035     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8036     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8037     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8038     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8039     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8040     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8041     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8042     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8043     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8044     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8045     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8046     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8047     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8048     { 0 }
8049 };
8050
8051 static void test_DestroyWindow(void)
8052 {
8053     BOOL ret;
8054     HWND parent, child1, child2, child3, child4, test;
8055     UINT child_id = WND_CHILD_ID + 1;
8056
8057     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8058                              100, 100, 200, 200, 0, 0, 0, NULL);
8059     assert(parent != 0);
8060     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8061                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8062     assert(child1 != 0);
8063     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8064                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8065     assert(child2 != 0);
8066     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8067                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8068     assert(child3 != 0);
8069     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8070                              0, 0, 50, 50, parent, 0, 0, NULL);
8071     assert(child4 != 0);
8072
8073     /* test owner/parent of child2 */
8074     test = GetParent(child2);
8075     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8076     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8077     if(pGetAncestor) {
8078         test = pGetAncestor(child2, GA_PARENT);
8079         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8080     }
8081     test = GetWindow(child2, GW_OWNER);
8082     ok(!test, "wrong owner %p\n", test);
8083
8084     test = SetParent(child2, parent);
8085     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8086
8087     /* test owner/parent of the parent */
8088     test = GetParent(parent);
8089     ok(!test, "wrong parent %p\n", test);
8090     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8091     if(pGetAncestor) {
8092         test = pGetAncestor(parent, GA_PARENT);
8093         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8094     }
8095     test = GetWindow(parent, GW_OWNER);
8096     ok(!test, "wrong owner %p\n", test);
8097
8098     /* test owner/parent of child1 */
8099     test = GetParent(child1);
8100     ok(test == parent, "wrong parent %p\n", test);
8101     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8102     if(pGetAncestor) {
8103         test = pGetAncestor(child1, GA_PARENT);
8104         ok(test == parent, "wrong parent %p\n", test);
8105     }
8106     test = GetWindow(child1, GW_OWNER);
8107     ok(!test, "wrong owner %p\n", test);
8108
8109     /* test owner/parent of child2 */
8110     test = GetParent(child2);
8111     ok(test == parent, "wrong parent %p\n", test);
8112     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8113     if(pGetAncestor) {
8114         test = pGetAncestor(child2, GA_PARENT);
8115         ok(test == parent, "wrong parent %p\n", test);
8116     }
8117     test = GetWindow(child2, GW_OWNER);
8118     ok(!test, "wrong owner %p\n", test);
8119
8120     /* test owner/parent of child3 */
8121     test = GetParent(child3);
8122     ok(test == child1, "wrong parent %p\n", test);
8123     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8124     if(pGetAncestor) {
8125         test = pGetAncestor(child3, GA_PARENT);
8126         ok(test == child1, "wrong parent %p\n", test);
8127     }
8128     test = GetWindow(child3, GW_OWNER);
8129     ok(!test, "wrong owner %p\n", test);
8130
8131     /* test owner/parent of child4 */
8132     test = GetParent(child4);
8133     ok(test == parent, "wrong parent %p\n", test);
8134     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8135     if(pGetAncestor) {
8136         test = pGetAncestor(child4, GA_PARENT);
8137         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8138     }
8139     test = GetWindow(child4, GW_OWNER);
8140     ok(test == parent, "wrong owner %p\n", test);
8141
8142     flush_sequence();
8143
8144     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8145            parent, child1, child2, child3, child4);
8146
8147     SetCapture(child4);
8148     test = GetCapture();
8149     ok(test == child4, "wrong capture window %p\n", test);
8150
8151     test_DestroyWindow_flag = TRUE;
8152     ret = DestroyWindow(parent);
8153     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8154     test_DestroyWindow_flag = FALSE;
8155     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8156
8157     ok(!IsWindow(parent), "parent still exists\n");
8158     ok(!IsWindow(child1), "child1 still exists\n");
8159     ok(!IsWindow(child2), "child2 still exists\n");
8160     ok(!IsWindow(child3), "child3 still exists\n");
8161     ok(!IsWindow(child4), "child4 still exists\n");
8162
8163     test = GetCapture();
8164     ok(!test, "wrong capture window %p\n", test);
8165 }
8166
8167
8168 static const struct message WmDispatchPaint[] = {
8169     { WM_NCPAINT, sent },
8170     { WM_GETTEXT, sent|defwinproc|optional },
8171     { WM_GETTEXT, sent|defwinproc|optional },
8172     { WM_ERASEBKGND, sent },
8173     { 0 }
8174 };
8175
8176 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8177 {
8178     if (message == WM_PAINT) return 0;
8179     return MsgCheckProcA( hwnd, message, wParam, lParam );
8180 }
8181
8182 static void test_DispatchMessage(void)
8183 {
8184     RECT rect;
8185     MSG msg;
8186     int count;
8187     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8188                                100, 100, 200, 200, 0, 0, 0, NULL);
8189     ShowWindow( hwnd, SW_SHOW );
8190     UpdateWindow( hwnd );
8191     flush_events();
8192     flush_sequence();
8193     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8194
8195     SetRect( &rect, -5, -5, 5, 5 );
8196     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8197     count = 0;
8198     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8199     {
8200         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8201         else
8202         {
8203             flush_sequence();
8204             DispatchMessage( &msg );
8205             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8206             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8207             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8208             if (++count > 10) break;
8209         }
8210     }
8211     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8212
8213     trace("now without DispatchMessage\n");
8214     flush_sequence();
8215     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8216     count = 0;
8217     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8218     {
8219         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8220         else
8221         {
8222             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8223             flush_sequence();
8224             /* this will send WM_NCCPAINT just like DispatchMessage does */
8225             GetUpdateRgn( hwnd, hrgn, TRUE );
8226             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8227             DeleteObject( hrgn );
8228             GetClientRect( hwnd, &rect );
8229             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8230             ok( !count, "Got multiple WM_PAINTs\n" );
8231             if (++count > 10) break;
8232         }
8233     }
8234     DestroyWindow(hwnd);
8235 }
8236
8237
8238 static const struct message WmUser[] = {
8239     { WM_USER, sent },
8240     { 0 }
8241 };
8242
8243 struct sendmsg_info
8244 {
8245     HWND  hwnd;
8246     DWORD timeout;
8247     DWORD ret;
8248 };
8249
8250 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8251 {
8252     struct sendmsg_info *info = arg;
8253     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8254     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
8255     return 0;
8256 }
8257
8258 static void wait_for_thread( HANDLE thread )
8259 {
8260     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8261     {
8262         MSG msg;
8263         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8264     }
8265 }
8266
8267 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8268 {
8269     if (message == WM_USER) Sleep(200);
8270     return MsgCheckProcA( hwnd, message, wParam, lParam );
8271 }
8272
8273 static void test_SendMessageTimeout(void)
8274 {
8275     HANDLE thread;
8276     struct sendmsg_info info;
8277     DWORD tid;
8278
8279     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8280                                100, 100, 200, 200, 0, 0, 0, NULL);
8281     flush_events();
8282     flush_sequence();
8283
8284     info.timeout = 1000;
8285     info.ret = 0xdeadbeef;
8286     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8287     wait_for_thread( thread );
8288     CloseHandle( thread );
8289     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8290     ok_sequence( WmUser, "WmUser", FALSE );
8291
8292     info.timeout = 1;
8293     info.ret = 0xdeadbeef;
8294     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8295     Sleep(100);  /* SendMessageTimeout should time out here */
8296     wait_for_thread( thread );
8297     CloseHandle( thread );
8298     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8299     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8300
8301     /* 0 means infinite timeout */
8302     info.timeout = 0;
8303     info.ret = 0xdeadbeef;
8304     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8305     Sleep(100);
8306     wait_for_thread( thread );
8307     CloseHandle( thread );
8308     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8309     ok_sequence( WmUser, "WmUser", FALSE );
8310
8311     /* timeout is treated as signed despite the prototype */
8312     info.timeout = 0x7fffffff;
8313     info.ret = 0xdeadbeef;
8314     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8315     Sleep(100);
8316     wait_for_thread( thread );
8317     CloseHandle( thread );
8318     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8319     ok_sequence( WmUser, "WmUser", FALSE );
8320
8321     info.timeout = 0x80000000;
8322     info.ret = 0xdeadbeef;
8323     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8324     Sleep(100);
8325     wait_for_thread( thread );
8326     CloseHandle( thread );
8327     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8328     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8329
8330     /* now check for timeout during message processing */
8331     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8332     info.timeout = 100;
8333     info.ret = 0xdeadbeef;
8334     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8335     wait_for_thread( thread );
8336     CloseHandle( thread );
8337     /* we should time out but still get the message */
8338     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8339     ok_sequence( WmUser, "WmUser", FALSE );
8340
8341     DestroyWindow( info.hwnd );
8342 }
8343
8344
8345 /****************** edit message test *************************/
8346 #define ID_EDIT 0x1234
8347 static const struct message sl_edit_setfocus[] =
8348 {
8349     { HCBT_SETFOCUS, hook },
8350     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8351     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8352     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8353     { WM_SETFOCUS, sent|wparam, 0 },
8354     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8355     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8356     { WM_CTLCOLOREDIT, sent|parent },
8357     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8358     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8359     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8360     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8361     { 0 }
8362 };
8363 static const struct message ml_edit_setfocus[] =
8364 {
8365     { HCBT_SETFOCUS, hook },
8366     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8367     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8368     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8369     { WM_SETFOCUS, sent|wparam, 0 },
8370     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8371     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8372     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8373     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8374     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8375     { 0 }
8376 };
8377 static const struct message sl_edit_killfocus[] =
8378 {
8379     { HCBT_SETFOCUS, hook },
8380     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8381     { WM_KILLFOCUS, sent|wparam, 0 },
8382     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8383     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8384     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8385     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8386     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8387     { 0 }
8388 };
8389 static const struct message sl_edit_lbutton_dblclk[] =
8390 {
8391     { WM_LBUTTONDBLCLK, sent },
8392     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8393     { 0 }
8394 };
8395 static const struct message sl_edit_lbutton_down[] =
8396 {
8397     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8398     { HCBT_SETFOCUS, hook },
8399     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8400     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8401     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8402     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8403     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8404     { WM_CTLCOLOREDIT, sent|parent },
8405     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8406     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8407     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8408     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8409     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8410     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8411     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8412     { WM_CTLCOLOREDIT, sent|parent|optional },
8413     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8414     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8415     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8416     { 0 }
8417 };
8418 static const struct message ml_edit_lbutton_down[] =
8419 {
8420     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8421     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8422     { HCBT_SETFOCUS, hook },
8423     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8424     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8425     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8426     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8427     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8428     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8429     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8430     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8431     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8432     { 0 }
8433 };
8434 static const struct message sl_edit_lbutton_up[] =
8435 {
8436     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8437     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8438     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8439     { WM_CAPTURECHANGED, sent|defwinproc },
8440     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8441     { 0 }
8442 };
8443 static const struct message ml_edit_lbutton_up[] =
8444 {
8445     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8446     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8447     { WM_CAPTURECHANGED, sent|defwinproc },
8448     { 0 }
8449 };
8450
8451 static WNDPROC old_edit_proc;
8452
8453 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8454 {
8455     static long defwndproc_counter = 0;
8456     LRESULT ret;
8457     struct message msg;
8458
8459     trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
8460
8461     /* explicitly ignore WM_GETICON message */
8462     if (message == WM_GETICON) return 0;
8463
8464     msg.message = message;
8465     msg.flags = sent|wparam|lparam;
8466     if (defwndproc_counter) msg.flags |= defwinproc;
8467     msg.wParam = wParam;
8468     msg.lParam = lParam;
8469     add_message(&msg);
8470
8471     defwndproc_counter++;
8472     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8473     defwndproc_counter--;
8474
8475     return ret;
8476 }
8477
8478 static void subclass_edit(void)
8479 {
8480     WNDCLASSA cls;
8481
8482     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8483
8484     old_edit_proc = cls.lpfnWndProc;
8485
8486     cls.hInstance = GetModuleHandle(0);
8487     cls.lpfnWndProc = edit_hook_proc;
8488     cls.lpszClassName = "my_edit_class";
8489     UnregisterClass(cls.lpszClassName, cls.hInstance);
8490     if (!RegisterClassA(&cls)) assert(0);
8491 }
8492
8493 static void test_edit_messages(void)
8494 {
8495     HWND hwnd, parent;
8496     DWORD dlg_code;
8497
8498     subclass_edit();
8499     log_all_parent_messages++;
8500
8501     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8502                              100, 100, 200, 200, 0, 0, 0, NULL);
8503     ok (parent != 0, "Failed to create parent window\n");
8504
8505     /* test single line edit */
8506     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8507                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8508     ok(hwnd != 0, "Failed to create edit window\n");
8509
8510     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8511     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8512
8513     ShowWindow(hwnd, SW_SHOW);
8514     UpdateWindow(hwnd);
8515     SetFocus(0);
8516     flush_sequence();
8517
8518     SetFocus(hwnd);
8519     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8520
8521     SetFocus(0);
8522     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8523
8524     SetFocus(0);
8525     ReleaseCapture();
8526     flush_sequence();
8527
8528     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8529     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8530
8531     SetFocus(0);
8532     ReleaseCapture();
8533     flush_sequence();
8534
8535     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8536     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8537
8538     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8539     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8540
8541     DestroyWindow(hwnd);
8542
8543     /* test multiline edit */
8544     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8545                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8546     ok(hwnd != 0, "Failed to create edit window\n");
8547
8548     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8549     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8550        "wrong dlg_code %08x\n", dlg_code);
8551
8552     ShowWindow(hwnd, SW_SHOW);
8553     UpdateWindow(hwnd);
8554     SetFocus(0);
8555     flush_sequence();
8556
8557     SetFocus(hwnd);
8558     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8559
8560     SetFocus(0);
8561     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8562
8563     SetFocus(0);
8564     ReleaseCapture();
8565     flush_sequence();
8566
8567     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8568     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8569
8570     SetFocus(0);
8571     ReleaseCapture();
8572     flush_sequence();
8573
8574     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8575     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8576
8577     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8578     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8579
8580     DestroyWindow(hwnd);
8581     DestroyWindow(parent);
8582
8583     log_all_parent_messages--;
8584 }
8585
8586 /**************************** End of Edit test ******************************/
8587
8588 static const struct message WmKeyDownSkippedSeq[] =
8589 {
8590     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8591     { 0 }
8592 };
8593 static const struct message WmKeyUpSkippedSeq[] =
8594 {
8595     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8596     { 0 }
8597 };
8598
8599 #define EV_START_STOP 0
8600 #define EV_SENDMSG 1
8601 #define EV_ACK 2
8602
8603 struct peekmsg_info
8604 {
8605     HWND  hwnd;
8606     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8607 };
8608
8609 static DWORD CALLBACK send_msg_thread_2(void *param)
8610 {
8611     DWORD ret;
8612     struct peekmsg_info *info = param;
8613
8614     trace("thread: waiting for start\n");
8615     WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
8616     trace("thread: looping\n");
8617
8618     while (1)
8619     {
8620         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8621
8622         switch (ret)
8623         {
8624         case WAIT_OBJECT_0 + EV_START_STOP:
8625             trace("thread: exiting\n");
8626             return 0;
8627
8628         case WAIT_OBJECT_0 + EV_SENDMSG:
8629             trace("thread: sending message\n");
8630             SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
8631             SetEvent(info->hevent[EV_ACK]);
8632             break;
8633
8634         default:
8635             trace("unexpected return: %04x\n", ret);
8636             assert(0);
8637             break;
8638         }
8639     }
8640     return 0;
8641 }
8642
8643 static void test_PeekMessage(void)
8644 {
8645     MSG msg;
8646     HANDLE hthread;
8647     DWORD tid, qstatus;
8648     UINT qs_all_input = QS_ALLINPUT;
8649     UINT qs_input = QS_INPUT;
8650     BOOL ret;
8651     struct peekmsg_info info;
8652
8653     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8654                               100, 100, 200, 200, 0, 0, 0, NULL);
8655     assert(info.hwnd);
8656     ShowWindow(info.hwnd, SW_SHOW);
8657     UpdateWindow(info.hwnd);
8658     SetFocus(info.hwnd);
8659
8660     info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
8661     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8662     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8663
8664     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8665     Sleep(100);
8666
8667     trace("signalling to start looping\n");
8668     SetEvent(info.hevent[EV_START_STOP]);
8669
8670     flush_events();
8671     flush_sequence();
8672
8673     SetLastError(0xdeadbeef);
8674     qstatus = GetQueueStatus(qs_all_input);
8675     if (GetLastError() == ERROR_INVALID_FLAGS)
8676     {
8677         trace("QS_RAWINPUT not supported on this platform\n");
8678         qs_all_input &= ~QS_RAWINPUT;
8679         qs_input &= ~QS_RAWINPUT;
8680     }
8681     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8682
8683     trace("signalling to send message\n");
8684     SetEvent(info.hevent[EV_SENDMSG]);
8685     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8686
8687     /* pass invalid QS_xxxx flags */
8688     SetLastError(0xdeadbeef);
8689     qstatus = GetQueueStatus(0xffffffff);
8690     ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
8691     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8692
8693     qstatus = GetQueueStatus(qs_all_input);
8694     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8695        "wrong qstatus %08x\n", qstatus);
8696
8697     msg.message = 0;
8698     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8699     ok(!ret,
8700        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8701         msg.message);
8702     ok_sequence(WmUser, "WmUser", FALSE);
8703
8704     qstatus = GetQueueStatus(qs_all_input);
8705     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8706
8707     keybd_event('N', 0, 0, 0);
8708     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8709     qstatus = GetQueueStatus(qs_all_input);
8710     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8711        "wrong qstatus %08x\n", qstatus);
8712
8713     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8714     qstatus = GetQueueStatus(qs_all_input);
8715     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8716        "wrong qstatus %08x\n", qstatus);
8717
8718     InvalidateRect(info.hwnd, NULL, FALSE);
8719     qstatus = GetQueueStatus(qs_all_input);
8720     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8721        "wrong qstatus %08x\n", qstatus);
8722
8723     trace("signalling to send message\n");
8724     SetEvent(info.hevent[EV_SENDMSG]);
8725     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8726
8727     qstatus = GetQueueStatus(qs_all_input);
8728     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8729        "wrong qstatus %08x\n", qstatus);
8730
8731     msg.message = 0;
8732     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8733     ok(!ret,
8734        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8735         msg.message);
8736     ok_sequence(WmUser, "WmUser", FALSE);
8737
8738     qstatus = GetQueueStatus(qs_all_input);
8739     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8740        "wrong qstatus %08x\n", qstatus);
8741
8742     trace("signalling to send message\n");
8743     SetEvent(info.hevent[EV_SENDMSG]);
8744     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8745
8746     qstatus = GetQueueStatus(qs_all_input);
8747     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8748        "wrong qstatus %08x\n", qstatus);
8749
8750     msg.message = 0;
8751     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8752     ok(!ret,
8753        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8754         msg.message);
8755     ok_sequence(WmUser, "WmUser", FALSE);
8756
8757     qstatus = GetQueueStatus(qs_all_input);
8758     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8759        "wrong qstatus %08x\n", qstatus);
8760
8761     msg.message = 0;
8762     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8763     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8764        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8765        ret, msg.message, msg.wParam);
8766     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8767
8768     qstatus = GetQueueStatus(qs_all_input);
8769     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8770        "wrong qstatus %08x\n", qstatus);
8771
8772     msg.message = 0;
8773     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8774     ok(!ret,
8775        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8776         msg.message);
8777     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8778
8779     qstatus = GetQueueStatus(qs_all_input);
8780     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8781        "wrong qstatus %08x\n", qstatus);
8782
8783     msg.message = 0;
8784     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8785     ok(ret && msg.message == WM_PAINT,
8786        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8787     DispatchMessageA(&msg);
8788     ok_sequence(WmPaint, "WmPaint", FALSE);
8789
8790     qstatus = GetQueueStatus(qs_all_input);
8791     ok(qstatus == MAKELONG(0, QS_KEY),
8792        "wrong qstatus %08x\n", qstatus);
8793
8794     msg.message = 0;
8795     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8796     ok(!ret,
8797        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8798         msg.message);
8799     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8800
8801     qstatus = GetQueueStatus(qs_all_input);
8802     ok(qstatus == MAKELONG(0, QS_KEY),
8803        "wrong qstatus %08x\n", qstatus);
8804
8805     trace("signalling to send message\n");
8806     SetEvent(info.hevent[EV_SENDMSG]);
8807     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8808
8809     qstatus = GetQueueStatus(qs_all_input);
8810     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8811        "wrong qstatus %08x\n", qstatus);
8812
8813     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8814
8815     qstatus = GetQueueStatus(qs_all_input);
8816     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8817        "wrong qstatus %08x\n", qstatus);
8818
8819     msg.message = 0;
8820     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8821     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8822        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8823        ret, msg.message, msg.wParam);
8824     ok_sequence(WmUser, "WmUser", FALSE);
8825
8826     qstatus = GetQueueStatus(qs_all_input);
8827     ok(qstatus == MAKELONG(0, QS_KEY),
8828        "wrong qstatus %08x\n", qstatus);
8829
8830     msg.message = 0;
8831     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8832     ok(!ret,
8833        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8834         msg.message);
8835     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8836
8837     qstatus = GetQueueStatus(qs_all_input);
8838     ok(qstatus == MAKELONG(0, QS_KEY),
8839        "wrong qstatus %08x\n", qstatus);
8840
8841     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8842
8843     qstatus = GetQueueStatus(qs_all_input);
8844     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8845        "wrong qstatus %08x\n", qstatus);
8846
8847     trace("signalling to send message\n");
8848     SetEvent(info.hevent[EV_SENDMSG]);
8849     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8850
8851     qstatus = GetQueueStatus(qs_all_input);
8852     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8853        "wrong qstatus %08x\n", qstatus);
8854
8855     msg.message = 0;
8856     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8857     ok(!ret,
8858        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8859         msg.message);
8860     ok_sequence(WmUser, "WmUser", FALSE);
8861
8862     qstatus = GetQueueStatus(qs_all_input);
8863     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8864        "wrong qstatus %08x\n", qstatus);
8865
8866     msg.message = 0;
8867     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8868         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8869     else /* workaround for a missing QS_RAWINPUT support */
8870         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8871     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8872        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8873        ret, msg.message, msg.wParam);
8874     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8875
8876     qstatus = GetQueueStatus(qs_all_input);
8877     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8878        "wrong qstatus %08x\n", qstatus);
8879
8880     msg.message = 0;
8881     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8882         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8883     else /* workaround for a missing QS_RAWINPUT support */
8884         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8885     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8886        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
8887        ret, msg.message, msg.wParam);
8888     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8889
8890     qstatus = GetQueueStatus(qs_all_input);
8891     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8892        "wrong qstatus %08x\n", qstatus);
8893
8894     msg.message = 0;
8895     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8896     ok(!ret,
8897        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8898         msg.message);
8899     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8900
8901     qstatus = GetQueueStatus(qs_all_input);
8902     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8903        "wrong qstatus %08x\n", qstatus);
8904
8905     msg.message = 0;
8906     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8907     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8908        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8909        ret, msg.message, msg.wParam);
8910     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8911
8912     qstatus = GetQueueStatus(qs_all_input);
8913     ok(qstatus == 0,
8914        "wrong qstatus %08x\n", qstatus);
8915
8916     msg.message = 0;
8917     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8918     ok(!ret,
8919        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8920         msg.message);
8921     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8922
8923     qstatus = GetQueueStatus(qs_all_input);
8924     ok(qstatus == 0,
8925        "wrong qstatus %08x\n", qstatus);
8926
8927     /* test whether presence of the quit flag in the queue affects
8928      * the queue state
8929      */
8930     PostQuitMessage(0x1234abcd);
8931
8932     qstatus = GetQueueStatus(qs_all_input);
8933     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8934        "wrong qstatus %08x\n", qstatus);
8935
8936     PostMessageA(info.hwnd, WM_USER, 0, 0);
8937
8938     qstatus = GetQueueStatus(qs_all_input);
8939     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8940        "wrong qstatus %08x\n", qstatus);
8941
8942     msg.message = 0;
8943     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8944     ok(ret && msg.message == WM_USER,
8945        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8946     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8947
8948     qstatus = GetQueueStatus(qs_all_input);
8949     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8950        "wrong qstatus %08x\n", qstatus);
8951
8952     msg.message = 0;
8953     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8954     ok(ret && msg.message == WM_QUIT,
8955        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8956     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
8957     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8958     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8959
8960     qstatus = GetQueueStatus(qs_all_input);
8961 todo_wine {
8962     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8963        "wrong qstatus %08x\n", qstatus);
8964 }
8965
8966     msg.message = 0;
8967     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8968     ok(!ret,
8969        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8970         msg.message);
8971     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8972
8973     qstatus = GetQueueStatus(qs_all_input);
8974     ok(qstatus == 0,
8975        "wrong qstatus %08x\n", qstatus);
8976
8977     trace("signalling to exit\n");
8978     SetEvent(info.hevent[EV_START_STOP]);
8979
8980     WaitForSingleObject(hthread, INFINITE);
8981
8982     CloseHandle(hthread);
8983     CloseHandle(info.hevent[0]);
8984     CloseHandle(info.hevent[1]);
8985     CloseHandle(info.hevent[2]);
8986
8987     DestroyWindow(info.hwnd);
8988 }
8989
8990 static void wait_move_event(HWND hwnd, int x, int y)
8991 {
8992     MSG msg;
8993     DWORD time;
8994     BOOL  ret;
8995     int go = 0;
8996
8997     time = GetTickCount();
8998     while (GetTickCount() - time < 200 && !go) {
8999         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9000         go  = ret && msg.pt.x > x && msg.pt.y > y;
9001     }
9002 }
9003
9004 #define STEP 20
9005 static void test_PeekMessage2(void)
9006 {
9007     HWND hwnd;
9008     BOOL ret;
9009     MSG msg;
9010     UINT message;
9011     DWORD time1, time2, time3;
9012     int x1, y1, x2, y2, x3, y3;
9013     POINT pos;
9014
9015     time1 = time2 = time3 = 0;
9016     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9017
9018     /* Initialise window and make sure it is ready for events */
9019     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9020                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9021     assert(hwnd);
9022     trace("Window for test_PeekMessage2 %p\n", hwnd);
9023     ShowWindow(hwnd, SW_SHOW);
9024     UpdateWindow(hwnd);
9025     SetFocus(hwnd);
9026     GetCursorPos(&pos);
9027     SetCursorPos(100, 100);
9028     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9029     flush_events();
9030
9031     /* Do initial mousemove, wait until we can see it
9032        and then do our test peek with PM_NOREMOVE. */
9033     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9034     wait_move_event(hwnd, 80, 80);
9035
9036     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9037     ok(ret, "no message available\n");
9038     if (ret) {
9039         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9040         message = msg.message;
9041         time1 = msg.time;
9042         x1 = msg.pt.x;
9043         y1 = msg.pt.y;
9044         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9045     }
9046
9047     /* Allow time to advance a bit, and then simulate the user moving their
9048      * mouse around. After that we peek again with PM_NOREMOVE.
9049      * Although the previous mousemove message was never removed, the
9050      * mousemove we now peek should reflect the recent mouse movements
9051      * because the input queue will merge the move events. */
9052     Sleep(2);
9053     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9054     wait_move_event(hwnd, x1, y1);
9055
9056     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9057     ok(ret, "no message available\n");
9058     if (ret) {
9059         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9060         message = msg.message;
9061         time2 = msg.time;
9062         x2 = msg.pt.x;
9063         y2 = msg.pt.y;
9064         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9065         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9066         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9067     }
9068
9069     /* Have another go, to drive the point home */
9070     Sleep(2);
9071     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9072     wait_move_event(hwnd, x2, y2);
9073
9074     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9075     ok(ret, "no message available\n");
9076     if (ret) {
9077         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9078         message = msg.message;
9079         time3 = msg.time;
9080         x3 = msg.pt.x;
9081         y3 = msg.pt.y;
9082         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9083         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9084         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9085     }
9086
9087     DestroyWindow(hwnd);
9088     SetCursorPos(pos.x, pos.y);
9089     flush_events();
9090 }
9091
9092 static void test_quit_message(void)
9093 {
9094     MSG msg;
9095     BOOL ret;
9096
9097     /* test using PostQuitMessage */
9098     PostQuitMessage(0xbeef);
9099
9100     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9101     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9102     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9103     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9104
9105     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9106     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9107
9108     ret = GetMessage(&msg, NULL, 0, 0);
9109     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9110     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9111
9112     /* note: WM_QUIT message received after WM_USER message */
9113     ret = GetMessage(&msg, NULL, 0, 0);
9114     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9115     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9116     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9117
9118     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9119     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9120
9121     /* now test with PostThreadMessage - different behaviour! */
9122     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9123
9124     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9125     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9126     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9127     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9128
9129     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9130     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9131
9132     /* note: we receive the WM_QUIT message first this time */
9133     ret = GetMessage(&msg, NULL, 0, 0);
9134     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9135     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9136     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9137
9138     ret = GetMessage(&msg, NULL, 0, 0);
9139     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9140     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9141 }
9142
9143 static const struct message WmMouseHoverSeq[] = {
9144     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9145     { WM_MOUSEACTIVATE, sent|optional },
9146     { WM_TIMER, sent|optional }, /* XP sends it */
9147     { WM_SYSTIMER, sent },
9148     { WM_MOUSEHOVER, sent|wparam, 0 },
9149     { 0 }
9150 };
9151
9152 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9153 {
9154     MSG msg;
9155     DWORD start_ticks, end_ticks;
9156
9157     start_ticks = GetTickCount();
9158     /* add some deviation (5%) to cover not expected delays */
9159     start_ticks += timeout / 20;
9160
9161     do
9162     {
9163         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9164         {
9165             /* Timer proc messages are not dispatched to the window proc,
9166              * and therefore not logged.
9167              */
9168             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9169             {
9170                 struct message s_msg;
9171
9172                 s_msg.message = msg.message;
9173                 s_msg.flags = sent|wparam|lparam;
9174                 s_msg.wParam = msg.wParam;
9175                 s_msg.lParam = msg.lParam;
9176                 add_message(&s_msg);
9177             }
9178             DispatchMessage(&msg);
9179         }
9180
9181         end_ticks = GetTickCount();
9182
9183         /* inject WM_MOUSEMOVE to see how it changes tracking */
9184         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9185         {
9186             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9187             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9188
9189             inject_mouse_move = FALSE;
9190         }
9191     } while (start_ticks + timeout >= end_ticks);
9192 }
9193
9194 static void test_TrackMouseEvent(void)
9195 {
9196     TRACKMOUSEEVENT tme;
9197     BOOL ret;
9198     HWND hwnd, hchild;
9199     RECT rc_parent, rc_child;
9200     UINT default_hover_time, hover_width = 0, hover_height = 0;
9201
9202 #define track_hover(track_hwnd, track_hover_time) \
9203     tme.cbSize = sizeof(tme); \
9204     tme.dwFlags = TME_HOVER; \
9205     tme.hwndTrack = track_hwnd; \
9206     tme.dwHoverTime = track_hover_time; \
9207     SetLastError(0xdeadbeef); \
9208     ret = pTrackMouseEvent(&tme); \
9209     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9210
9211 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9212     tme.cbSize = sizeof(tme); \
9213     tme.dwFlags = TME_QUERY; \
9214     tme.hwndTrack = (HWND)0xdeadbeef; \
9215     tme.dwHoverTime = 0xdeadbeef; \
9216     SetLastError(0xdeadbeef); \
9217     ret = pTrackMouseEvent(&tme); \
9218     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9219     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9220     ok(tme.dwFlags == (expected_track_flags), \
9221        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9222     ok(tme.hwndTrack == (expected_track_hwnd), \
9223        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9224     ok(tme.dwHoverTime == (expected_hover_time), \
9225        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9226
9227 #define track_hover_cancel(track_hwnd) \
9228     tme.cbSize = sizeof(tme); \
9229     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9230     tme.hwndTrack = track_hwnd; \
9231     tme.dwHoverTime = 0xdeadbeef; \
9232     SetLastError(0xdeadbeef); \
9233     ret = pTrackMouseEvent(&tme); \
9234     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9235
9236     default_hover_time = 0xdeadbeef;
9237     SetLastError(0xdeadbeef);
9238     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9239     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9240     if (!ret) default_hover_time = 400;
9241     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9242
9243     SetLastError(0xdeadbeef);
9244     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9245     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9246     if (!ret) hover_width = 4;
9247     SetLastError(0xdeadbeef);
9248     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9249     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9250     if (!ret) hover_height = 4;
9251     trace("hover rect is %u x %d\n", hover_width, hover_height);
9252
9253     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9254                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9255                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9256                           NULL, NULL, 0);
9257     assert(hwnd);
9258
9259     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9260                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9261                           50, 50, 200, 200, hwnd,
9262                           NULL, NULL, 0);
9263     assert(hchild);
9264
9265     flush_events();
9266     flush_sequence();
9267
9268     tme.cbSize = 0;
9269     tme.dwFlags = TME_QUERY;
9270     tme.hwndTrack = (HWND)0xdeadbeef;
9271     tme.dwHoverTime = 0xdeadbeef;
9272     SetLastError(0xdeadbeef);
9273     ret = pTrackMouseEvent(&tme);
9274     ok(!ret, "TrackMouseEvent should fail\n");
9275     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
9276
9277     tme.cbSize = sizeof(tme);
9278     tme.dwFlags = TME_HOVER;
9279     tme.hwndTrack = (HWND)0xdeadbeef;
9280     tme.dwHoverTime = 0xdeadbeef;
9281     SetLastError(0xdeadbeef);
9282     ret = pTrackMouseEvent(&tme);
9283     ok(!ret, "TrackMouseEvent should fail\n");
9284     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
9285
9286     tme.cbSize = sizeof(tme);
9287     tme.dwFlags = TME_HOVER | TME_CANCEL;
9288     tme.hwndTrack = (HWND)0xdeadbeef;
9289     tme.dwHoverTime = 0xdeadbeef;
9290     SetLastError(0xdeadbeef);
9291     ret = pTrackMouseEvent(&tme);
9292     ok(!ret, "TrackMouseEvent should fail\n");
9293     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
9294
9295     GetWindowRect(hwnd, &rc_parent);
9296     GetWindowRect(hchild, &rc_child);
9297     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9298
9299     /* Process messages so that the system updates its internal current
9300      * window and hittest, otherwise TrackMouseEvent calls don't have any
9301      * effect.
9302      */
9303     flush_events();
9304     flush_sequence();
9305
9306     track_query(0, NULL, 0);
9307     track_hover(hchild, 0);
9308     track_query(0, NULL, 0);
9309
9310     flush_events();
9311     flush_sequence();
9312
9313     track_hover(hwnd, 0);
9314     track_query(TME_HOVER, hwnd, default_hover_time);
9315
9316     pump_msg_loop_timeout(default_hover_time, FALSE);
9317     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9318
9319     track_query(0, NULL, 0);
9320
9321     track_hover(hwnd, HOVER_DEFAULT);
9322     track_query(TME_HOVER, hwnd, default_hover_time);
9323
9324     Sleep(default_hover_time / 2);
9325     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9326     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9327
9328     track_query(TME_HOVER, hwnd, default_hover_time);
9329
9330     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
9331     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9332
9333     track_query(0, NULL, 0);
9334
9335     track_hover(hwnd, HOVER_DEFAULT);
9336     track_query(TME_HOVER, hwnd, default_hover_time);
9337
9338     pump_msg_loop_timeout(default_hover_time, TRUE);
9339     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9340
9341     track_query(0, NULL, 0);
9342
9343     track_hover(hwnd, HOVER_DEFAULT);
9344     track_query(TME_HOVER, hwnd, default_hover_time);
9345     track_hover_cancel(hwnd);
9346
9347     DestroyWindow(hwnd);
9348
9349 #undef track_hover
9350 #undef track_query
9351 #undef track_hover_cancel
9352 }
9353
9354
9355 static const struct message WmSetWindowRgn[] = {
9356     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9357     { WM_NCCALCSIZE, sent|wparam, 1 },
9358     { WM_NCPAINT, sent }, /* wparam != 1 */
9359     { WM_GETTEXT, sent|defwinproc|optional },
9360     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9361     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9362     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9363     { 0 }
9364 };
9365
9366 static const struct message WmSetWindowRgn_no_redraw[] = {
9367     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9368     { WM_NCCALCSIZE, sent|wparam, 1 },
9369     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9370     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9371     { 0 }
9372 };
9373
9374 static const struct message WmSetWindowRgn_clear[] = {
9375     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9376     { WM_NCCALCSIZE, sent|wparam, 1 },
9377     { WM_NCPAINT, sent }, /* wparam != 1 */
9378     { WM_GETTEXT, sent|defwinproc|optional },
9379     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9380     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9381     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9382     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9383     { WM_GETTEXT, sent|defwinproc|optional },
9384     { WM_ERASEBKGND, sent|optional },
9385     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9386     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9387     { 0 }
9388 };
9389
9390 static void test_SetWindowRgn(void)
9391 {
9392     HRGN hrgn;
9393     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9394                                 100, 100, 200, 200, 0, 0, 0, NULL);
9395     ok( hwnd != 0, "Failed to create overlapped window\n" );
9396
9397     ShowWindow( hwnd, SW_SHOW );
9398     UpdateWindow( hwnd );
9399     flush_events();
9400     flush_sequence();
9401
9402     trace("testing SetWindowRgn\n");
9403     hrgn = CreateRectRgn( 0, 0, 150, 150 );
9404     SetWindowRgn( hwnd, hrgn, TRUE );
9405     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9406
9407     hrgn = CreateRectRgn( 30, 30, 160, 160 );
9408     SetWindowRgn( hwnd, hrgn, FALSE );
9409     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9410
9411     hrgn = CreateRectRgn( 0, 0, 180, 180 );
9412     SetWindowRgn( hwnd, hrgn, TRUE );
9413     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9414
9415     SetWindowRgn( hwnd, 0, TRUE );
9416     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9417
9418     DestroyWindow( hwnd );
9419 }
9420
9421 /*************************** ShowWindow() test ******************************/
9422 static const struct message WmShowNormal[] = {
9423     { WM_SHOWWINDOW, sent|wparam, 1 },
9424     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9425     { HCBT_ACTIVATE, hook },
9426     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9427     { HCBT_SETFOCUS, hook },
9428     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9429     { 0 }
9430 };
9431 static const struct message WmShow[] = {
9432     { WM_SHOWWINDOW, sent|wparam, 1 },
9433     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9434     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9435     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9436     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9437     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9438     { 0 }
9439 };
9440 static const struct message WmShowNoActivate_1[] = {
9441     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9442     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9443     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9444     { WM_MOVE, sent|defwinproc },
9445     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9446     { 0 }
9447 };
9448 static const struct message WmShowNoActivate_2[] = {
9449     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9450     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9451     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9452     { WM_MOVE, sent|defwinproc },
9453     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9454     { HCBT_SETFOCUS, hook|optional },
9455     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9456     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9457     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9458     { 0 }
9459 };
9460 static const struct message WmShowNA_1[] = {
9461     { WM_SHOWWINDOW, sent|wparam, 1 },
9462     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9463     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9464     { 0 }
9465 };
9466 static const struct message WmShowNA_2[] = {
9467     { WM_SHOWWINDOW, sent|wparam, 1 },
9468     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9469     { 0 }
9470 };
9471 static const struct message WmRestore_1[] = {
9472     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9473     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9474     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9475     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9476     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9477     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9478     { WM_MOVE, sent|defwinproc },
9479     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9480     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9481     { 0 }
9482 };
9483 static const struct message WmRestore_2[] = {
9484     { WM_SHOWWINDOW, sent|wparam, 1 },
9485     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9486     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9487     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9488     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9489     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9490     { 0 }
9491 };
9492 static const struct message WmRestore_3[] = {
9493     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9494     { WM_GETMINMAXINFO, sent },
9495     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9496     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9497     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9498     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9499     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9500     { WM_MOVE, sent|defwinproc },
9501     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9502     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9503     { 0 }
9504 };
9505 static const struct message WmRestore_4[] = {
9506     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9507     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9508     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9509     { WM_MOVE, sent|defwinproc },
9510     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9511     { 0 }
9512 };
9513 static const struct message WmRestore_5[] = {
9514     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9516     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9517     { WM_MOVE, sent|defwinproc },
9518     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9519     { 0 }
9520 };
9521 static const struct message WmHide_1[] = {
9522     { WM_SHOWWINDOW, sent|wparam, 0 },
9523     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9524     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9525     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9526     { 0 }
9527 };
9528 static const struct message WmHide_2[] = {
9529     { WM_SHOWWINDOW, sent|wparam, 0 },
9530     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9531     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9532     { 0 }
9533 };
9534 static const struct message WmHide_3[] = {
9535     { WM_SHOWWINDOW, sent|wparam, 0 },
9536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9537     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9538     { HCBT_SETFOCUS, hook },
9539     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9540     { 0 }
9541 };
9542 static const struct message WmShowMinimized_1[] = {
9543     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9544     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9545     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9546     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9547     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9548     { WM_MOVE, sent|defwinproc },
9549     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9550     { 0 }
9551 };
9552 static const struct message WmMinimize_1[] = {
9553     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9554     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9555     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9556     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9557     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9558     { WM_MOVE, sent|defwinproc },
9559     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9560     { 0 }
9561 };
9562 static const struct message WmMinimize_2[] = {
9563     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9564     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9565     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9566     { WM_MOVE, sent|defwinproc },
9567     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9568     { 0 }
9569 };
9570 static const struct message WmMinimize_3[] = {
9571     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9572     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9573     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9574     { WM_MOVE, sent|defwinproc },
9575     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9576     { 0 }
9577 };
9578 static const struct message WmShowMinNoActivate[] = {
9579     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9580     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9581     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9582     { 0 }
9583 };
9584 static const struct message WmMinMax_1[] = {
9585     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9586     { 0 }
9587 };
9588 static const struct message WmMinMax_2[] = {
9589     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9590     { 0 }
9591 };
9592 static const struct message WmMinMax_3[] = {
9593     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9594     { 0 }
9595 };
9596 static const struct message WmMinMax_4[] = {
9597     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9598     { 0 }
9599 };
9600 static const struct message WmShowMaximized_1[] = {
9601     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9602     { WM_GETMINMAXINFO, sent },
9603     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9604     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9605     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9606     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9607     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9608     { WM_MOVE, sent|defwinproc },
9609     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9610     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9611     { 0 }
9612 };
9613 static const struct message WmShowMaximized_2[] = {
9614     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9615     { WM_GETMINMAXINFO, sent },
9616     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
9617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9618     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
9619     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
9620     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9621     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9622     { WM_MOVE, sent|defwinproc },
9623     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9624     { HCBT_SETFOCUS, hook },
9625     { 0 }
9626 };
9627 static const struct message WmShowMaximized_3[] = {
9628     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9629     { WM_GETMINMAXINFO, sent },
9630     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9631     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9632     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9633     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9634     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9635     { WM_MOVE, sent|defwinproc },
9636     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9637     { 0 }
9638 };
9639
9640 static void test_ShowWindow(void)
9641 {
9642     /* ShowWindow commands in random order */
9643     static const struct
9644     {
9645         INT cmd; /* ShowWindow command */
9646         LPARAM ret; /* ShowWindow return value */
9647         DWORD style; /* window style after the command */
9648         const struct message *msg; /* message sequence the command produces */
9649         BOOL todo_msg; /* message sequence doesn't match what Wine does */
9650     } sw[] =
9651     {
9652 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
9653 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9654 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9655 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9656 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
9657 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
9658 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
9659 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9660 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
9661 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9662 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
9663 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
9664 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
9665 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9666 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
9667 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9668 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
9669 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9670 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
9671 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9672 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9673 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
9674 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
9675 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9676 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9677 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
9678 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
9679 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9680 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9681 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
9682 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9683 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
9684 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9685 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
9686 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
9687 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9688 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
9689 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9690 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9691 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
9692 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9693 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
9694 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9695 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
9696 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9697 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
9698 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
9699 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
9700 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
9701 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
9702 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9703 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9704 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9705 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
9706 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9707 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
9708 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
9709     };
9710     HWND hwnd;
9711     DWORD style;
9712     LPARAM ret;
9713     INT i;
9714
9715 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
9716     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
9717                           120, 120, 90, 90,
9718                           0, 0, 0, NULL);
9719     assert(hwnd);
9720
9721     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9722     ok(style == 0, "expected style 0, got %08x\n", style);
9723
9724     flush_events();
9725     flush_sequence();
9726
9727     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
9728     {
9729         static const char * const sw_cmd_name[13] =
9730         {
9731             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
9732             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
9733             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
9734             "SW_NORMALNA" /* 0xCC */
9735         };
9736         char comment[64];
9737         INT idx; /* index into the above array of names */
9738
9739         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
9740
9741         style = GetWindowLong(hwnd, GWL_STYLE);
9742         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
9743         ret = ShowWindow(hwnd, sw[i].cmd);
9744         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
9745         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9746         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
9747
9748         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
9749         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
9750
9751         flush_events();
9752         flush_sequence();
9753     }
9754
9755     DestroyWindow(hwnd);
9756 }
9757
9758 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9759 {
9760     struct message msg;
9761
9762     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
9763
9764     switch (message)
9765     {
9766     case WM_WINDOWPOSCHANGING:
9767     case WM_WINDOWPOSCHANGED:
9768     {
9769         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
9770
9771         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
9772         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
9773               winpos->hwnd, winpos->hwndInsertAfter,
9774               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
9775         dump_winpos_flags(winpos->flags);
9776
9777         /* Log only documented flags, win2k uses 0x1000 and 0x2000
9778          * in the high word for internal purposes
9779          */
9780         wParam = winpos->flags & 0xffff;
9781         /* We are not interested in the flags that don't match under XP and Win9x */
9782         wParam &= ~(SWP_NOZORDER);
9783         break;
9784     }
9785
9786     /* explicitly ignore WM_GETICON message */
9787     case WM_GETICON:
9788         return 0;
9789     }
9790
9791     msg.message = message;
9792     msg.flags = sent|wparam|lparam;
9793     msg.wParam = wParam;
9794     msg.lParam = lParam;
9795     add_message(&msg);
9796
9797     /* calling DefDlgProc leads to a recursion under XP */
9798
9799     switch (message)
9800     {
9801     case WM_INITDIALOG:
9802     case WM_GETDLGCODE:
9803         return 0;
9804     }
9805     return 1;
9806 }
9807
9808 static const struct message WmDefDlgSetFocus_1[] = {
9809     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9810     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9811     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9812     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9813     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9814     { HCBT_SETFOCUS, hook },
9815     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9816     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9817     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9818     { WM_SETFOCUS, sent|wparam, 0 },
9819     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9820     { WM_CTLCOLOREDIT, sent },
9821     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9822     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9823     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9824     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9825     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
9826     { 0 }
9827 };
9828 static const struct message WmDefDlgSetFocus_2[] = {
9829     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9830     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9831     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9832     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9833     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9834     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9835     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
9836     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9837     { 0 }
9838 };
9839 /* Creation of a dialog */
9840 static const struct message WmCreateDialogParamSeq_1[] = {
9841     { HCBT_CREATEWND, hook },
9842     { WM_NCCREATE, sent },
9843     { WM_NCCALCSIZE, sent|wparam, 0 },
9844     { WM_CREATE, sent },
9845     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9846     { WM_SIZE, sent|wparam, SIZE_RESTORED },
9847     { WM_MOVE, sent },
9848     { WM_SETFONT, sent },
9849     { WM_INITDIALOG, sent },
9850     { WM_CHANGEUISTATE, sent|optional },
9851     { 0 }
9852 };
9853 /* Creation of a dialog */
9854 static const struct message WmCreateDialogParamSeq_2[] = {
9855     { HCBT_CREATEWND, hook },
9856     { WM_NCCREATE, sent },
9857     { WM_NCCALCSIZE, sent|wparam, 0 },
9858     { WM_CREATE, sent },
9859     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9860     { WM_SIZE, sent|wparam, SIZE_RESTORED },
9861     { WM_MOVE, sent },
9862     { WM_CHANGEUISTATE, sent|optional },
9863     { 0 }
9864 };
9865
9866 static void test_dialog_messages(void)
9867 {
9868     WNDCLASS cls;
9869     HWND hdlg, hedit1, hedit2, hfocus;
9870     LRESULT ret;
9871
9872 #define set_selection(hctl, start, end) \
9873     ret = SendMessage(hctl, EM_SETSEL, start, end); \
9874     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
9875
9876 #define check_selection(hctl, start, end) \
9877     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
9878     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
9879
9880     subclass_edit();
9881
9882     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
9883                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
9884                           0, 0, 100, 100, 0, 0, 0, NULL);
9885     ok(hdlg != 0, "Failed to create custom dialog window\n");
9886
9887     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
9888                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9889                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
9890     ok(hedit1 != 0, "Failed to create edit control\n");
9891     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
9892                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9893                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
9894     ok(hedit2 != 0, "Failed to create edit control\n");
9895
9896     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
9897     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
9898
9899     hfocus = GetFocus();
9900     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
9901
9902     SetFocus(hedit2);
9903     hfocus = GetFocus();
9904     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
9905
9906     check_selection(hedit1, 0, 0);
9907     check_selection(hedit2, 0, 0);
9908
9909     set_selection(hedit2, 0, -1);
9910     check_selection(hedit2, 0, 3);
9911
9912     SetFocus(0);
9913     hfocus = GetFocus();
9914     ok(hfocus == 0, "wrong focus %p\n", hfocus);
9915
9916     flush_sequence();
9917     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9918     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9919     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
9920
9921     hfocus = GetFocus();
9922     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9923
9924     check_selection(hedit1, 0, 5);
9925     check_selection(hedit2, 0, 3);
9926
9927     flush_sequence();
9928     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9929     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9930     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
9931
9932     hfocus = GetFocus();
9933     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9934
9935     check_selection(hedit1, 0, 5);
9936     check_selection(hedit2, 0, 3);
9937
9938     EndDialog(hdlg, 0);
9939     DestroyWindow(hedit1);
9940     DestroyWindow(hedit2);
9941     DestroyWindow(hdlg);
9942     flush_sequence();
9943
9944 #undef set_selection
9945 #undef check_selection
9946
9947     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
9948     cls.lpszClassName = "MyDialogClass";
9949     cls.hInstance = GetModuleHandle(0);
9950     /* need a cast since a dlgproc is used as a wndproc */
9951     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
9952     if (!RegisterClass(&cls)) assert(0);
9953
9954     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
9955     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9956     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
9957     EndDialog(hdlg, 0);
9958     DestroyWindow(hdlg);
9959     flush_sequence();
9960
9961     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
9962     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9963     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
9964     EndDialog(hdlg, 0);
9965     DestroyWindow(hdlg);
9966     flush_sequence();
9967
9968     UnregisterClass(cls.lpszClassName, cls.hInstance);
9969 }
9970
9971 static void test_nullCallback(void)
9972 {
9973     HWND hwnd;
9974
9975     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9976                            100, 100, 200, 200, 0, 0, 0, NULL);
9977     ok (hwnd != 0, "Failed to create overlapped window\n");
9978
9979     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
9980     flush_events();
9981     DestroyWindow(hwnd);
9982 }
9983
9984 /* SetActiveWindow( 0 ) hwnd visible */
9985 static const struct message SetActiveWindowSeq0[] =
9986 {
9987     { HCBT_ACTIVATE, hook },
9988     { WM_NCACTIVATE, sent|wparam, 0 },
9989     { WM_GETTEXT, sent|defwinproc|optional },
9990     { WM_ACTIVATE, sent|wparam, 0 },
9991     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
9992     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
9993     { WM_NCACTIVATE, sent|wparam, 1 },
9994     { WM_GETTEXT, sent|defwinproc|optional },
9995     { WM_ACTIVATE, sent|wparam, 1 },
9996     { HCBT_SETFOCUS, hook },
9997     { WM_KILLFOCUS, sent|defwinproc },
9998     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
9999     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10000     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10001     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10002     { WM_SETFOCUS, sent|defwinproc },
10003     { 0 }
10004 };
10005 /* SetActiveWindow( hwnd ) hwnd visible */
10006 static const struct message SetActiveWindowSeq1[] =
10007 {
10008     { 0 }
10009 };
10010 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10011 static const struct message SetActiveWindowSeq2[] =
10012 {
10013     { HCBT_ACTIVATE, hook },
10014     { WM_NCACTIVATE, sent|wparam, 0 },
10015     { WM_GETTEXT, sent|defwinproc|optional },
10016     { WM_ACTIVATE, sent|wparam, 0 },
10017     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10018     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10019     { WM_NCPAINT, sent|optional },
10020     { WM_GETTEXT, sent|defwinproc|optional },
10021     { WM_ERASEBKGND, sent|optional },
10022     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10023     { WM_NCACTIVATE, sent|wparam, 1 },
10024     { WM_ACTIVATE, sent|wparam, 1 },
10025     { HCBT_SETFOCUS, hook },
10026     { WM_KILLFOCUS, sent|defwinproc },
10027     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10028     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10029     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10030     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10031     { WM_SETFOCUS, sent|defwinproc },
10032     { 0 }
10033 };
10034
10035 /* SetActiveWindow( hwnd ) hwnd not visible */
10036 static const struct message SetActiveWindowSeq3[] =
10037 {
10038     { HCBT_ACTIVATE, hook },
10039     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10040     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10041     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10042     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10043     { WM_ACTIVATEAPP, sent|wparam, 1 },
10044     { WM_ACTIVATEAPP, sent|wparam, 1 },
10045     { WM_NCACTIVATE, sent|wparam, 1 },
10046     { WM_ACTIVATE, sent|wparam, 1 },
10047     { HCBT_SETFOCUS, hook },
10048     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10049     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10050     { WM_SETFOCUS, sent|defwinproc },
10051     { 0 }
10052 };
10053 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10054 static const struct message SetActiveWindowSeq4[] =
10055 {
10056     { HCBT_ACTIVATE, hook },
10057     { WM_NCACTIVATE, sent|wparam, 0 },
10058     { WM_GETTEXT, sent|defwinproc|optional },
10059     { WM_ACTIVATE, sent|wparam, 0 },
10060     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10061     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10062     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10063     { WM_NCACTIVATE, sent|wparam, 1 },
10064     { WM_ACTIVATE, sent|wparam, 1 },
10065     { HCBT_SETFOCUS, hook },
10066     { WM_KILLFOCUS, sent|defwinproc },
10067     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10068     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10069     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10070     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10071     { WM_SETFOCUS, sent|defwinproc },
10072     { 0 }
10073 };
10074
10075
10076 static void test_SetActiveWindow(void)
10077 {
10078     HWND hwnd, popup, ret;
10079
10080     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10081                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10082                            100, 100, 200, 200, 0, 0, 0, NULL);
10083
10084     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10085                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10086                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10087
10088     ok(hwnd != 0, "Failed to create overlapped window\n");
10089     flush_sequence();
10090
10091     ok(popup != 0, "Failed to create popup window\n");
10092     flush_sequence();
10093
10094     trace("SetActiveWindow(0)\n");
10095     ret = SetActiveWindow(0);
10096     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10097     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", TRUE);
10098     flush_sequence();
10099
10100     trace("SetActiveWindow(hwnd), hwnd visible\n");
10101     ret = SetActiveWindow(hwnd);
10102     todo_wine
10103     {
10104         ok( ret == hwnd, "Failed to SetActiveWindow(hwnd), hwnd visible\n");
10105     }
10106     ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10107     flush_sequence();
10108
10109     trace("SetActiveWindow(popup), hwnd visible, popup visble\n");
10110     ret = SetActiveWindow(popup);
10111     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visble\n");
10112     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visble", TRUE);
10113     flush_sequence();
10114
10115     ShowWindow(hwnd, SW_HIDE);
10116     ShowWindow(popup, SW_HIDE);
10117     flush_sequence();
10118
10119     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10120     ret = SetActiveWindow(hwnd);
10121     ok( ret == NULL, "Failed to SetActiveWindow(hwnd), hwnd not visible\n");
10122     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10123     flush_sequence();
10124
10125     trace("SetActiveWindow(popup), hwnd not visible, popup not visble\n");
10126     ret = SetActiveWindow(popup);
10127     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10128     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visble", TRUE);
10129     flush_sequence();
10130
10131     trace("done\n");
10132
10133     DestroyWindow(hwnd);
10134 }
10135
10136 static const struct message SetForegroundWindowSeq[] =
10137 {
10138     { WM_NCACTIVATE, sent|wparam, 0 },
10139     { WM_GETTEXT, sent|defwinproc|optional },
10140     { WM_ACTIVATE, sent|wparam, 0 },
10141     { WM_ACTIVATEAPP, sent|wparam, 0 },
10142     { WM_KILLFOCUS, sent },
10143     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10144     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10145     { 0 }
10146 };
10147
10148 static void test_SetForegroundWindow(void)
10149 {
10150     HWND hwnd;
10151
10152     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10153                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10154                            100, 100, 200, 200, 0, 0, 0, NULL);
10155     ok (hwnd != 0, "Failed to create overlapped window\n");
10156     flush_sequence();
10157
10158     trace("SetForegroundWindow( 0 )\n");
10159     SetForegroundWindow( 0 );
10160     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10161     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10162     SetForegroundWindow( GetDesktopWindow() );
10163     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10164                                         "foreground top level window", FALSE);
10165     trace("done\n");
10166
10167     DestroyWindow(hwnd);
10168 }
10169
10170 static void test_dbcs_wm_char(void)
10171 {
10172     BYTE dbch[2];
10173     WCHAR wch, bad_wch;
10174     HWND hwnd, hwnd2;
10175     MSG msg;
10176     DWORD time;
10177     POINT pt;
10178     DWORD_PTR res;
10179     CPINFOEXA cpinfo;
10180     UINT i, j, k;
10181     struct message wmCharSeq[2];
10182
10183     if (!pGetCPInfoExA)
10184     {
10185         skip("GetCPInfoExA is not available\n");
10186         return;
10187     }
10188
10189     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10190     if (cpinfo.MaxCharSize != 2)
10191     {
10192         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10193         return;
10194     }
10195
10196     dbch[0] = dbch[1] = 0;
10197     wch = 0;
10198     bad_wch = cpinfo.UnicodeDefaultChar;
10199     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10200         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10201             for (k = 128; k <= 255; k++)
10202             {
10203                 char str[2];
10204                 WCHAR wstr[2];
10205                 str[0] = j;
10206                 str[1] = k;
10207                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10208                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10209                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10210                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10211                 {
10212                     dbch[0] = j;
10213                     dbch[1] = k;
10214                     wch = wstr[0];
10215                     break;
10216                 }
10217             }
10218
10219     if (!wch)
10220     {
10221         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10222         return;
10223     }
10224     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10225            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10226
10227     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10228                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10229     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10230                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10231     ok (hwnd != 0, "Failed to create overlapped window\n");
10232     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10233     flush_sequence();
10234
10235     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10236     wmCharSeq[0].message = WM_CHAR;
10237     wmCharSeq[0].flags = sent|wparam;
10238     wmCharSeq[0].wParam = wch;
10239
10240     /* posted message */
10241     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10242     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10243     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10244     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10245     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10246     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10247     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10248
10249     /* posted thread message */
10250     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10251     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10252     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10253     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10254     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10255     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10256     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10257
10258     /* sent message */
10259     flush_sequence();
10260     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10261     ok_sequence( WmEmptySeq, "no messages", FALSE );
10262     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10263     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10264     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10265
10266     /* sent message with timeout */
10267     flush_sequence();
10268     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10269     ok_sequence( WmEmptySeq, "no messages", FALSE );
10270     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10271     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10272     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10273
10274     /* sent message with timeout and callback */
10275     flush_sequence();
10276     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10277     ok_sequence( WmEmptySeq, "no messages", FALSE );
10278     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10279     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10280     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10281
10282     /* sent message with callback */
10283     flush_sequence();
10284     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10285     ok_sequence( WmEmptySeq, "no messages", FALSE );
10286     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10287     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10288     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10289
10290     /* direct window proc call */
10291     flush_sequence();
10292     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10293     ok_sequence( WmEmptySeq, "no messages", FALSE );
10294     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10295     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10296
10297     /* dispatch message */
10298     msg.hwnd = hwnd;
10299     msg.message = WM_CHAR;
10300     msg.wParam = dbch[0];
10301     msg.lParam = 0;
10302     DispatchMessageA( &msg );
10303     ok_sequence( WmEmptySeq, "no messages", FALSE );
10304     msg.wParam = dbch[1];
10305     DispatchMessageA( &msg );
10306     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10307
10308     /* window handle is irrelevant */
10309     flush_sequence();
10310     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10311     ok_sequence( WmEmptySeq, "no messages", FALSE );
10312     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10313     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10314     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10315
10316     /* interleaved post and send */
10317     flush_sequence();
10318     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10319     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10320     ok_sequence( WmEmptySeq, "no messages", FALSE );
10321     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10322     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10323     ok_sequence( WmEmptySeq, "no messages", FALSE );
10324     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10325     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10326     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10327     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10328     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10329     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10330     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10331
10332     /* interleaved sent message and winproc */
10333     flush_sequence();
10334     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10335     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10336     ok_sequence( WmEmptySeq, "no messages", FALSE );
10337     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10338     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10339     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10340     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10341
10342     /* interleaved winproc and dispatch */
10343     msg.hwnd = hwnd;
10344     msg.message = WM_CHAR;
10345     msg.wParam = dbch[0];
10346     msg.lParam = 0;
10347     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10348     DispatchMessageA( &msg );
10349     ok_sequence( WmEmptySeq, "no messages", FALSE );
10350     msg.wParam = dbch[1];
10351     DispatchMessageA( &msg );
10352     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10353     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10354     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10355
10356     /* interleaved sends */
10357     flush_sequence();
10358     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10359     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10360     ok_sequence( WmEmptySeq, "no messages", FALSE );
10361     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10362     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10363     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10364     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10365
10366     /* dbcs WM_CHAR */
10367     flush_sequence();
10368     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10369     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10370     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10371
10372     /* other char messages are not magic */
10373     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10374     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10375     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10376     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10377     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10378     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10379     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10380     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10381     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10382     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10383
10384     /* test retrieving messages */
10385
10386     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10387     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10388     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10389     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10390     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10391     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10392     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10393     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10394     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10395     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10396
10397     /* message filters */
10398     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10399     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10400     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10401     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10402     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10403     /* message id is filtered, hwnd is not */
10404     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10405     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10406     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10407     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10408     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10409     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10410
10411     /* mixing GetMessage and PostMessage */
10412     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10413     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10414     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10415     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10416     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10417     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10418     time = msg.time;
10419     pt = msg.pt;
10420     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
10421     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10422     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10423     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10424     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10425     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10426     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
10427     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 );
10428     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10429
10430     /* without PM_REMOVE */
10431     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10432     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10433     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10434     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10435     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10436     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10437     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10438     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10439     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10440     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10441     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10442     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10443     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10444     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10445     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10446     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10447     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10448     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10449
10450     DestroyWindow(hwnd);
10451 }
10452
10453 #define ID_LISTBOX 0x000f
10454
10455 static const struct message wm_lb_setcursel_0[] =
10456 {
10457     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
10458     { WM_CTLCOLORLISTBOX, sent|parent },
10459     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10460     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10461     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10462     { 0 }
10463 };
10464 static const struct message wm_lb_setcursel_1[] =
10465 {
10466     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
10467     { WM_CTLCOLORLISTBOX, sent|parent },
10468     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
10469     { WM_CTLCOLORLISTBOX, sent|parent },
10470     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
10471     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10472     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10473     { 0 }
10474 };
10475 static const struct message wm_lb_setcursel_2[] =
10476 {
10477     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
10478     { WM_CTLCOLORLISTBOX, sent|parent },
10479     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
10480     { WM_CTLCOLORLISTBOX, sent|parent },
10481     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
10482     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10483     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10484     { 0 }
10485 };
10486 static const struct message wm_lb_click_0[] =
10487 {
10488     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10489     { HCBT_SETFOCUS, hook },
10490     { WM_KILLFOCUS, sent|parent },
10491     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10492     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10493     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10494     { WM_SETFOCUS, sent|defwinproc },
10495
10496     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10497     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10498     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10499     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10500     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10501
10502     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10503     { WM_CTLCOLORLISTBOX, sent|parent },
10504     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10505     { WM_CTLCOLORLISTBOX, sent|parent },
10506     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10507     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
10508
10509     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10510     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10511
10512     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10513     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10514     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
10515     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
10516     { 0 }
10517 };
10518
10519 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
10520
10521 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
10522
10523 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10524 {
10525     static long defwndproc_counter = 0;
10526     LRESULT ret;
10527     struct message msg;
10528
10529     /* do not log painting messages */
10530     if (message != WM_PAINT &&
10531         message != WM_NCPAINT &&
10532         message != WM_SYNCPAINT &&
10533         message != WM_ERASEBKGND &&
10534         message != WM_NCHITTEST &&
10535         message != WM_GETTEXT &&
10536         message != WM_GETICON &&
10537         message != WM_DEVICECHANGE)
10538     {
10539         trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10540
10541         msg.message = message;
10542         msg.flags = sent|wparam|lparam;
10543         if (defwndproc_counter) msg.flags |= defwinproc;
10544         msg.wParam = wp;
10545         msg.lParam = lp;
10546         add_message(&msg);
10547     }
10548
10549     defwndproc_counter++;
10550     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
10551     defwndproc_counter--;
10552
10553     return ret;
10554 }
10555
10556 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
10557                                int caret_index, int top_index, int line)
10558 {
10559     LRESULT ret;
10560
10561     /* calling an orig proc helps to avoid unnecessary message logging */
10562     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
10563     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
10564     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
10565     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
10566     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
10567     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
10568     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
10569     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
10570 }
10571
10572 static void test_listbox_messages(void)
10573 {
10574     HWND parent, listbox;
10575     LRESULT ret;
10576
10577     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
10578                              100, 100, 200, 200, 0, 0, 0, NULL);
10579     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
10580                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10581                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
10582     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
10583
10584     check_lb_state(listbox, 0, LB_ERR, 0, 0);
10585
10586     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
10587     ok(ret == 0, "expected 0, got %ld\n", ret);
10588     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
10589     ok(ret == 1, "expected 1, got %ld\n", ret);
10590     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
10591     ok(ret == 2, "expected 2, got %ld\n", ret);
10592
10593     check_lb_state(listbox, 3, LB_ERR, 0, 0);
10594
10595     flush_sequence();
10596
10597     log_all_parent_messages++;
10598
10599     trace("selecting item 0\n");
10600     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
10601     ok(ret == 0, "expected 0, got %ld\n", ret);
10602     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
10603     check_lb_state(listbox, 3, 0, 0, 0);
10604     flush_sequence();
10605
10606     trace("selecting item 1\n");
10607     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
10608     ok(ret == 1, "expected 1, got %ld\n", ret);
10609     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
10610     check_lb_state(listbox, 3, 1, 1, 0);
10611
10612     trace("selecting item 2\n");
10613     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
10614     ok(ret == 2, "expected 2, got %ld\n", ret);
10615     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
10616     check_lb_state(listbox, 3, 2, 2, 0);
10617
10618     trace("clicking on item 0\n");
10619     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
10620     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10621     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
10622     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10623     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
10624     check_lb_state(listbox, 3, 0, 0, 0);
10625     flush_sequence();
10626
10627     log_all_parent_messages--;
10628
10629     DestroyWindow(listbox);
10630     DestroyWindow(parent);
10631 }
10632
10633 /*************************** Menu test ******************************/
10634 static const struct message wm_popup_menu_1[] =
10635 {
10636     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10637     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10638     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
10639     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
10640     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
10641     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
10642     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
10643     { WM_INITMENU, sent|lparam, 0, 0 },
10644     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
10645     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
10646     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
10647     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
10648     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
10649     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
10650     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
10651     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
10652     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10653     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
10654     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
10655     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
10656     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
10657     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
10658     { 0 }
10659 };
10660 static const struct message wm_popup_menu_2[] =
10661 {
10662     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10663     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10664     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
10665     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
10666     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
10667     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
10668     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
10669     { WM_INITMENU, sent|lparam, 0, 0 },
10670     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
10671     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
10672     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
10673     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
10674     { HCBT_CREATEWND, hook },
10675     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
10676                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
10677     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
10678     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
10679     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
10680     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
10681     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
10682     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
10683     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
10684     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
10685     { HCBT_DESTROYWND, hook },
10686     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10687     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
10688     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10689     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
10690     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
10691     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
10692     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
10693     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
10694     { 0 }
10695 };
10696 static const struct message wm_popup_menu_3[] =
10697 {
10698     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10699     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10700     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
10701     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
10702     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
10703     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
10704     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
10705     { WM_INITMENU, sent|lparam, 0, 0 },
10706     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
10707     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
10708     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
10709     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
10710     { HCBT_CREATEWND, hook },
10711     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
10712                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
10713     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
10714     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
10715     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
10716     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
10717     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
10718     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
10719     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
10720     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
10721     { HCBT_DESTROYWND, hook },
10722     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10723     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
10724     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
10725     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
10726     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
10727     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
10728     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
10729     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
10730     { 0 }
10731 };
10732
10733 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10734 {
10735     if (message == WM_ENTERIDLE ||
10736         message == WM_INITMENU ||
10737         message == WM_INITMENUPOPUP ||
10738         message == WM_MENUSELECT ||
10739         message == WM_PARENTNOTIFY ||
10740         message == WM_ENTERMENULOOP ||
10741         message == WM_EXITMENULOOP ||
10742         message == WM_UNINITMENUPOPUP ||
10743         message == WM_KEYDOWN ||
10744         message == WM_KEYUP ||
10745         message == WM_CHAR ||
10746         message == WM_SYSKEYDOWN ||
10747         message == WM_SYSKEYUP ||
10748         message == WM_SYSCHAR ||
10749         message == WM_COMMAND ||
10750         message == WM_MENUCOMMAND)
10751     {
10752         struct message msg;
10753
10754         trace("parent_menu_proc: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10755
10756         msg.message = message;
10757         msg.flags = sent|wparam|lparam;
10758         msg.wParam = wp;
10759         msg.lParam = lp;
10760         add_message(&msg);
10761     }
10762
10763     return DefWindowProcA(hwnd, message, wp, lp);
10764 }
10765
10766 static void set_menu_style(HMENU hmenu, DWORD style)
10767 {
10768     MENUINFO mi;
10769     BOOL ret;
10770
10771     mi.cbSize = sizeof(mi);
10772     mi.fMask = MIM_STYLE;
10773     mi.dwStyle = style;
10774     SetLastError(0xdeadbeef);
10775     ret = pSetMenuInfo(hmenu, &mi);
10776     ok(ret, "SetMenuInfo error %u\n", GetLastError());
10777 }
10778
10779 static DWORD get_menu_style(HMENU hmenu)
10780 {
10781     MENUINFO mi;
10782     BOOL ret;
10783
10784     mi.cbSize = sizeof(mi);
10785     mi.fMask = MIM_STYLE;
10786     mi.dwStyle = 0;
10787     SetLastError(0xdeadbeef);
10788     ret = pGetMenuInfo(hmenu, &mi);
10789     ok(ret, "GetMenuInfo error %u\n", GetLastError());
10790
10791     return mi.dwStyle;
10792 }
10793
10794 static void test_menu_messages(void)
10795 {
10796     MSG msg;
10797     WNDCLASSA cls;
10798     HMENU hmenu, hmenu_popup;
10799     HWND hwnd;
10800     DWORD style;
10801
10802     if (!pGetMenuInfo || !pSetMenuInfo)
10803     {
10804         skip("GetMenuInfo and/or SetMenuInfo are not available\n");
10805         return;
10806     }
10807     cls.style = 0;
10808     cls.lpfnWndProc = parent_menu_proc;
10809     cls.cbClsExtra = 0;
10810     cls.cbWndExtra = 0;
10811     cls.hInstance = GetModuleHandleA(0);
10812     cls.hIcon = 0;
10813     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
10814     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
10815     cls.lpszMenuName = NULL;
10816     cls.lpszClassName = "TestMenuClass";
10817     UnregisterClass(cls.lpszClassName, cls.hInstance);
10818     if (!RegisterClassA(&cls)) assert(0);
10819
10820     SetLastError(0xdeadbeef);
10821     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10822                            100, 100, 200, 200, 0, 0, 0, NULL);
10823     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
10824
10825     SetLastError(0xdeadbeef);
10826     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
10827     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
10828
10829     SetMenu(hwnd, hmenu);
10830
10831     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
10832     style = get_menu_style(hmenu);
10833     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
10834
10835     hmenu_popup = GetSubMenu(hmenu, 0);
10836     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
10837     style = get_menu_style(hmenu_popup);
10838     ok(style == 0, "expected 0, got %u\n", style);
10839
10840     hmenu_popup = GetSubMenu(hmenu_popup, 0);
10841     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
10842     style = get_menu_style(hmenu_popup);
10843     ok(style == 0, "expected 0, got %u\n", style);
10844
10845     /* Alt+E, Enter */
10846     trace("testing a popup menu command\n");
10847     flush_sequence();
10848     keybd_event(VK_MENU, 0, 0, 0);
10849     keybd_event('E', 0, 0, 0);
10850     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
10851     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10852     keybd_event(VK_RETURN, 0, 0, 0);
10853     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
10854     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10855     {
10856         TranslateMessage(&msg);
10857         DispatchMessage(&msg);
10858     }
10859     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
10860
10861     /* Alt+F, Right, Enter */
10862     trace("testing submenu of a popup menu command\n");
10863     flush_sequence();
10864     keybd_event(VK_MENU, 0, 0, 0);
10865     keybd_event('F', 0, 0, 0);
10866     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
10867     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10868     keybd_event(VK_RIGHT, 0, 0, 0);
10869     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
10870     keybd_event(VK_RETURN, 0, 0, 0);
10871     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
10872     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10873     {
10874         TranslateMessage(&msg);
10875         DispatchMessage(&msg);
10876     }
10877     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
10878
10879     set_menu_style(hmenu, 0);
10880     style = get_menu_style(hmenu);
10881     ok(style == 0, "expected 0, got %u\n", style);
10882
10883     hmenu_popup = GetSubMenu(hmenu, 0);
10884     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
10885     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
10886     style = get_menu_style(hmenu_popup);
10887     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
10888
10889     hmenu_popup = GetSubMenu(hmenu_popup, 0);
10890     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
10891     style = get_menu_style(hmenu_popup);
10892     ok(style == 0, "expected 0, got %u\n", style);
10893
10894     /* Alt+F, Right, Enter */
10895     trace("testing submenu of a popup menu command\n");
10896     flush_sequence();
10897     keybd_event(VK_MENU, 0, 0, 0);
10898     keybd_event('F', 0, 0, 0);
10899     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
10900     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
10901     keybd_event(VK_RIGHT, 0, 0, 0);
10902     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
10903     keybd_event(VK_RETURN, 0, 0, 0);
10904     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
10905     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10906     {
10907         TranslateMessage(&msg);
10908         DispatchMessage(&msg);
10909     }
10910     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
10911
10912     DestroyWindow(hwnd);
10913     DestroyMenu(hmenu);
10914 }
10915
10916 START_TEST(msg)
10917 {
10918     BOOL ret;
10919     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
10920
10921     init_procs();
10922
10923     if (!RegisterWindowClasses()) assert(0);
10924
10925     if (pSetWinEventHook)
10926     {
10927         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
10928                                                       GetModuleHandleA(0),
10929                                                       win_event_proc,
10930                                                       0,
10931                                                       GetCurrentThreadId(),
10932                                                       WINEVENT_INCONTEXT);
10933         assert(hEvent_hook);
10934
10935         if (pIsWinEventHookInstalled)
10936         {
10937             UINT event;
10938             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
10939                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
10940         }
10941     }
10942
10943     cbt_hook_thread_id = GetCurrentThreadId();
10944     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
10945     assert(hCBT_hook);
10946
10947     test_winevents();
10948
10949     /* Fix message sequences before removing 4 lines below */
10950 #if 1
10951     if (pUnhookWinEvent && hEvent_hook)
10952     {
10953         ret = pUnhookWinEvent(hEvent_hook);
10954         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10955         pUnhookWinEvent = 0;
10956     }
10957     hEvent_hook = 0;
10958 #endif
10959
10960     test_ShowWindow();
10961     test_PeekMessage();
10962     test_PeekMessage2();
10963     test_scrollwindowex();
10964     test_messages();
10965     test_showwindow();
10966     invisible_parent_tests();
10967     test_mdi_messages();
10968     test_button_messages();
10969     test_static_messages();
10970     test_listbox_messages();
10971     test_combobox_messages();
10972     test_wmime_keydown_message();
10973     test_paint_messages();
10974     test_interthread_messages();
10975     test_message_conversion();
10976     test_accelerators();
10977     test_timers();
10978     test_timers_no_wnd();
10979     test_set_hook();
10980     test_DestroyWindow();
10981     test_DispatchMessage();
10982     test_SendMessageTimeout();
10983     test_edit_messages();
10984     test_quit_message();
10985     test_SetActiveWindow();
10986
10987     if (!pTrackMouseEvent)
10988         skip("TrackMouseEvent is not available\n");
10989     else
10990         test_TrackMouseEvent();
10991
10992     test_SetWindowRgn();
10993     test_sys_menu();
10994     test_dialog_messages();
10995     test_nullCallback();
10996     test_dbcs_wm_char();
10997     test_menu_messages();
10998     /* keep it the last test, under Windows it tends to break the tests
10999      * which rely on active/foreground windows being correct.
11000      */
11001     test_SetForegroundWindow();
11002
11003     UnhookWindowsHookEx(hCBT_hook);
11004     if (pUnhookWinEvent)
11005     {
11006         ret = pUnhookWinEvent(hEvent_hook);
11007         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11008         SetLastError(0xdeadbeef);
11009         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11010         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11011            GetLastError() == 0xdeadbeef, /* Win9x */
11012            "unexpected error %d\n", GetLastError());
11013     }
11014     else
11015         skip("UnhookWinEvent is not available\n");
11016 }