cryptnet: Add CertDllVerifyRevocation stub.
[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_SYSTIMER
47 #define WM_SYSTIMER         0x0118
48 #endif
49
50 #define WND_PARENT_ID           1
51 #define WND_POPUP_ID            2
52 #define WND_CHILD_ID            3
53
54 /* encoded DRAWITEMSTRUCT into an LPARAM */
55 typedef struct
56 {
57     union
58     {
59         struct
60         {
61             UINT type    : 4;  /* ODT_* flags */
62             UINT ctl_id  : 4;  /* Control ID */
63             UINT item_id : 4;  /* Menu item ID */
64             UINT action  : 4;  /* ODA_* flags */
65             UINT state   : 16; /* ODS_* flags */
66         } item;
67         LPARAM lp;
68     } u;
69 } DRAW_ITEM_STRUCT;
70
71 static BOOL test_DestroyWindow_flag;
72 static HWINEVENTHOOK hEvent_hook;
73
74 static void dump_winpos_flags(UINT flags);
75
76 static const WCHAR testWindowClassW[] =
77 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
78
79 /*
80 FIXME: add tests for these
81 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
82  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
83  WS_THICKFRAME: thick border
84  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
85  WS_BORDER (default for overlapped windows): single black border
86  none (default for child (and popup?) windows): no border
87 */
88
89 typedef enum {
90     sent=0x1,
91     posted=0x2,
92     parent=0x4,
93     wparam=0x8,
94     lparam=0x10,
95     defwinproc=0x20,
96     beginpaint=0x40,
97     optional=0x80,
98     hook=0x100,
99     winevent_hook=0x200
100 } msg_flags_t;
101
102 struct message {
103     UINT message;          /* the WM_* code */
104     msg_flags_t flags;     /* message props */
105     WPARAM wParam;         /* expected value of wParam */
106     LPARAM lParam;         /* expected value of lParam */
107 };
108
109 /* Empty message sequence */
110 static const struct message WmEmptySeq[] =
111 {
112     { 0 }
113 };
114 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
115 static const struct message WmCreateOverlappedSeq[] = {
116     { HCBT_CREATEWND, hook },
117     { WM_GETMINMAXINFO, sent },
118     { WM_NCCREATE, sent },
119     { WM_NCCALCSIZE, sent|wparam, 0 },
120     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
121     { WM_CREATE, sent },
122     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
123     { 0 }
124 };
125 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
126  * for a not visible overlapped window.
127  */
128 static const struct message WmSWP_ShowOverlappedSeq[] = {
129     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
130     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
131     { WM_NCPAINT, sent|wparam|optional, 1 },
132     { WM_GETTEXT, sent|defwinproc|optional },
133     { WM_ERASEBKGND, sent|optional },
134     { HCBT_ACTIVATE, hook },
135     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
136     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
137     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
138     { WM_ACTIVATEAPP, sent|wparam, 1 },
139     { WM_NCACTIVATE, sent|wparam, 1 },
140     { WM_GETTEXT, sent|defwinproc|optional },
141     { WM_ACTIVATE, sent|wparam, 1 },
142     { HCBT_SETFOCUS, hook },
143     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
144     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
145     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
146     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
147     { WM_NCPAINT, sent|wparam|optional, 1 },
148     { WM_GETTEXT, sent|defwinproc|optional },
149     { WM_ERASEBKGND, sent|optional },
150     /* Win9x adds SWP_NOZORDER below */
151     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
152     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
153     { WM_NCPAINT, sent|wparam|optional, 1 },
154     { WM_ERASEBKGND, sent|optional },
155     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
156     { 0 }
157 };
158 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
159  * for a visible overlapped window.
160  */
161 static const struct message WmSWP_HideOverlappedSeq[] = {
162     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
163     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
164     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
165     { 0 }
166 };
167
168 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
169  * for a visible overlapped window.
170  */
171 static const struct message WmSWP_ResizeSeq[] = {
172     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
173     { WM_GETMINMAXINFO, sent|defwinproc },
174     { WM_NCCALCSIZE, sent|wparam, TRUE },
175     { WM_NCPAINT, sent|optional },
176     { WM_GETTEXT, sent|defwinproc|optional },
177     { WM_ERASEBKGND, sent|optional },
178     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
179     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
180     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
181     { WM_NCPAINT, sent|optional },
182     { WM_GETTEXT, sent|defwinproc|optional },
183     { WM_ERASEBKGND, sent|optional },
184     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
185     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
186     { 0 }
187 };
188
189 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
190  * for a visible popup window.
191  */
192 static const struct message WmSWP_ResizePopupSeq[] = {
193     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
194     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
195     { WM_NCCALCSIZE, sent|wparam, TRUE },
196     { WM_NCPAINT, sent|optional },
197     { WM_GETTEXT, sent|defwinproc|optional },
198     { WM_ERASEBKGND, sent|optional },
199     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
200     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
201     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
202     { WM_NCPAINT, sent|optional },
203     { WM_GETTEXT, sent|defwinproc|optional },
204     { WM_ERASEBKGND, sent|optional },
205     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
206     { 0 }
207 };
208
209 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
210  * for a visible overlapped window.
211  */
212 static const struct message WmSWP_MoveSeq[] = {
213     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
214     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
215     { WM_MOVE, sent|defwinproc|wparam, 0 },
216     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
217     { 0 }
218 };
219 /* Resize with SetWindowPos(SWP_NOZORDER)
220  * for a visible overlapped window
221  * SWP_NOZORDER is stripped by the logging code
222  */
223 static const struct message WmSWP_ResizeNoZOrder[] = {
224     { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
225     { WM_GETMINMAXINFO, sent|defwinproc },
226     { WM_NCCALCSIZE, sent|wparam, 1 },
227     { WM_NCPAINT, sent },
228     { WM_GETTEXT, sent|defwinproc|optional },
229     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
230     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
231     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
232     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
233     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
234     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
235     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
236     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
237     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
238     { 0 }
239 };
240
241 /* Switch visible mdi children */
242 static const struct message WmSwitchChild[] = {
243     /* Switch MDI child */
244     { WM_MDIACTIVATE, sent },/* in the MDI client */
245     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
246     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
247     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
248     /* Deactivate 2nd MDI child */
249     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
250     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
251     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
252     /* Preparing for maximize and maximaze the 1st MDI child */
253     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
254     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
255     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
256     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
257     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 }, /* in the 1st MDI child */
258     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
259     /* Lock redraw 2nd MDI child */
260     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
261     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
262     /* Restore 2nd MDI child */
263     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },/* in the 2nd MDI child */
264     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
265     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
266     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 }, /* in the 2nd MDI child */
267     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
268     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
269     /* Redraw 2nd MDI child */
270     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
271     /* Redraw MDI frame */
272     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
273     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
274     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
275     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
276     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
277     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
278     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
279     { HCBT_SETFOCUS, hook },
280     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
281     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
282     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
283     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
284     { WM_SETFOCUS, sent },/* in the MDI client */
285     { HCBT_SETFOCUS, hook },
286     { WM_KILLFOCUS, sent },/* in the MDI client */
287     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
288     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
289     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
290     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
291     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
292     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
293     { 0 }
294 };
295
296 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
297                 SWP_NOZORDER|SWP_FRAMECHANGED)
298  * for a visible overlapped window with WS_CLIPCHILDREN style set.
299  */
300 static const struct message WmSWP_FrameChanged_clip[] = {
301     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
302     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
303     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
304     { WM_GETTEXT, sent|parent|defwinproc|optional },
305     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
306     { WM_NCPAINT, sent }, /* wparam != 1 */
307     { WM_ERASEBKGND, sent },
308     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
309     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
310     { WM_PAINT, sent },
311     { 0 }
312 };
313 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
314                 SWP_NOZORDER|SWP_FRAMECHANGED)
315  * for a visible overlapped window.
316  */
317 static const struct message WmSWP_FrameChangedDeferErase[] = {
318     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
319     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
320     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
321     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
322     { WM_PAINT, sent|parent },
323     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
324     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
325     { WM_PAINT, sent },
326     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
327     { WM_ERASEBKGND, sent|beginpaint },
328     { 0 }
329 };
330
331 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
332                 SWP_NOZORDER|SWP_FRAMECHANGED)
333  * for a visible overlapped window without WS_CLIPCHILDREN style set.
334  */
335 static const struct message WmSWP_FrameChanged_noclip[] = {
336     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
337     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
338     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
339     { WM_GETTEXT, sent|parent|defwinproc|optional },
340     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
341     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
342     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
343     { WM_PAINT, sent },
344     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
345     { WM_ERASEBKGND, sent|beginpaint },
346     { 0 }
347 };
348
349 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
350 static const struct message WmShowOverlappedSeq[] = {
351     { WM_SHOWWINDOW, sent|wparam, 1 },
352     { WM_NCPAINT, sent|wparam|optional, 1 },
353     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
354     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
355     { WM_NCPAINT, sent|wparam|optional, 1 },
356     { WM_GETTEXT, sent|defwinproc|optional },
357     { WM_ERASEBKGND, sent|optional },
358     { HCBT_ACTIVATE, hook },
359     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
360     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
361     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
362     { WM_NCPAINT, sent|wparam|optional, 1 },
363     { WM_ACTIVATEAPP, sent|wparam, 1 },
364     { WM_NCACTIVATE, sent|wparam, 1 },
365     { WM_GETTEXT, sent|defwinproc|optional },
366     { WM_ACTIVATE, sent|wparam, 1 },
367     { HCBT_SETFOCUS, hook },
368     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
369     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
370     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
371     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
372     { WM_NCPAINT, sent|wparam|optional, 1 },
373     { WM_GETTEXT, sent|defwinproc|optional },
374     { WM_ERASEBKGND, sent|optional },
375     /* Win9x adds SWP_NOZORDER below */
376     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
377     { WM_NCCALCSIZE, sent|optional },
378     { WM_NCPAINT, sent|optional },
379     { WM_ERASEBKGND, sent|optional },
380 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
381        * messages. Does that mean that CreateWindow doesn't set initial
382        * window dimensions for overlapped windows?
383        */
384     { WM_SIZE, sent },
385     { WM_MOVE, sent },
386 #endif
387     { 0 }
388 };
389 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
390 static const struct message WmShowMaxOverlappedSeq[] = {
391     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
392     { WM_GETMINMAXINFO, sent },
393     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
394     { WM_GETMINMAXINFO, sent|defwinproc },
395     { WM_NCCALCSIZE, sent|wparam, TRUE },
396     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
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_ACTIVATEAPP, sent|wparam, 1 },
402     { WM_NCACTIVATE, sent|wparam, 1 },
403     { WM_GETTEXT, sent|defwinproc|optional },
404     { WM_ACTIVATE, sent|wparam, 1 },
405     { HCBT_SETFOCUS, hook },
406     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
407     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
408     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
409     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
410     { WM_NCPAINT, sent|wparam|optional, 1 },
411     { WM_GETTEXT, sent|defwinproc|optional },
412     { WM_ERASEBKGND, sent|optional },
413     /* Win9x adds SWP_NOZORDER below */
414     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
415     { WM_MOVE, sent|defwinproc },
416     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
417     { WM_NCCALCSIZE, sent|optional },
418     { WM_NCPAINT, sent|optional },
419     { WM_ERASEBKGND, sent|optional },
420     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
421     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
422     { 0 }
423 };
424 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
425 static const struct message WmShowMinOverlappedSeq[] = {
426     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
427     { HCBT_SETFOCUS, hook },
428     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
429     { WM_KILLFOCUS, sent },
430     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
431     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
432     { WM_GETTEXT, sent|optional },
433     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
434     { WM_GETMINMAXINFO, sent|defwinproc },
435     { WM_NCCALCSIZE, sent|wparam, TRUE },
436     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
437     { WM_NCPAINT, sent },
438     { WM_GETTEXT, sent|defwinproc|optional },
439     { WM_WINDOWPOSCHANGED, sent },
440     { WM_MOVE, sent|defwinproc },
441     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
442     { WM_NCCALCSIZE, sent|optional },
443     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
444     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
445     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
446     { WM_NCACTIVATE, sent|wparam, 0 },
447     { WM_GETTEXT, sent|defwinproc|optional },
448     { WM_ACTIVATE, sent },
449     { WM_ACTIVATEAPP, sent|wparam, 0 },
450     { 0 }
451 };
452 /* ShowWindow(SW_HIDE) for a visible overlapped window */
453 static const struct message WmHideOverlappedSeq[] = {
454     { WM_SHOWWINDOW, sent|wparam, 0 },
455     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
456     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
457     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
458     { WM_SIZE, sent|optional }, /* XP doesn't send it */
459     { WM_MOVE, sent|optional }, /* XP doesn't send it */
460     { WM_NCACTIVATE, sent|wparam, 0 },
461     { WM_ACTIVATE, sent|wparam, 0 },
462     { WM_ACTIVATEAPP, sent|wparam, 0 },
463     { WM_KILLFOCUS, sent|wparam, 0 },
464     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
465     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
466     { 0 }
467 };
468 /* DestroyWindow for a visible overlapped window */
469 static const struct message WmDestroyOverlappedSeq[] = {
470     { HCBT_DESTROYWND, hook },
471     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
472     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
473     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
474     { WM_NCACTIVATE, sent|wparam, 0 },
475     { WM_ACTIVATE, sent|wparam, 0 },
476     { WM_ACTIVATEAPP, sent|wparam, 0 },
477     { WM_KILLFOCUS, sent|wparam, 0 },
478     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
479     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
480     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
481     { WM_DESTROY, sent },
482     { WM_NCDESTROY, sent },
483     { 0 }
484 };
485 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
486 static const struct message WmCreateMaxPopupSeq[] = {
487     { HCBT_CREATEWND, hook },
488     { WM_NCCREATE, sent },
489     { WM_NCCALCSIZE, sent|wparam, 0 },
490     { WM_CREATE, sent },
491     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
492     { WM_SIZE, sent|wparam, SIZE_RESTORED },
493     { WM_MOVE, sent },
494     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
495     { WM_GETMINMAXINFO, sent },
496     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
497     { WM_NCCALCSIZE, sent|wparam, TRUE },
498     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
499     { WM_MOVE, sent|defwinproc },
500     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
501     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
502     { WM_SHOWWINDOW, sent|wparam, 1 },
503     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
504     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
505     { HCBT_ACTIVATE, hook },
506     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
507     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
508     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
509     { WM_ACTIVATEAPP, sent|wparam, 1 },
510     { WM_NCACTIVATE, sent|wparam, 1 },
511     { WM_ACTIVATE, sent|wparam, 1 },
512     { HCBT_SETFOCUS, hook },
513     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
514     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
515     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
516     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
517     { WM_SYNCPAINT, sent|wparam|optional, 4 },
518     { WM_NCPAINT, sent|wparam|optional, 1 },
519     { WM_ERASEBKGND, sent|optional },
520     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
521     { 0 }
522 };
523 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
524 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
525     { HCBT_CREATEWND, hook },
526     { WM_NCCREATE, sent },
527     { WM_NCCALCSIZE, sent|wparam, 0 },
528     { WM_CREATE, sent },
529     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
530     { WM_SIZE, sent|wparam, SIZE_RESTORED },
531     { WM_MOVE, sent },
532     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
533     { WM_GETMINMAXINFO, sent },
534     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
535     { WM_NCCALCSIZE, sent|wparam, TRUE },
536     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
537     { WM_MOVE, sent|defwinproc },
538     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
539     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
540     { 0 }
541 };
542 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
543 static const struct message WmShowMaxPopupResizedSeq[] = {
544     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
545     { WM_GETMINMAXINFO, sent },
546     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
547     { WM_NCCALCSIZE, sent|wparam, TRUE },
548     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
549     { HCBT_ACTIVATE, hook },
550     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
551     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
552     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
553     { WM_ACTIVATEAPP, sent|wparam, 1 },
554     { WM_NCACTIVATE, sent|wparam, 1 },
555     { WM_ACTIVATE, sent|wparam, 1 },
556     { HCBT_SETFOCUS, hook },
557     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
558     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
559     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
560     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
561     { WM_NCPAINT, sent|wparam|optional, 1 },
562     { WM_ERASEBKGND, sent|optional },
563     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
564     /* WinNT4.0 sends WM_MOVE */
565     { WM_MOVE, sent|defwinproc|optional },
566     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
567     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
568     { 0 }
569 };
570 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
571 static const struct message WmShowMaxPopupSeq[] = {
572     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
573     { WM_GETMINMAXINFO, sent },
574     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
575     { WM_NCCALCSIZE, sent|wparam, TRUE },
576     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
577     { HCBT_ACTIVATE, hook },
578     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
579     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
580     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
581     { WM_ACTIVATEAPP, sent|wparam, 1 },
582     { WM_NCACTIVATE, sent|wparam, 1 },
583     { WM_ACTIVATE, sent|wparam, 1 },
584     { HCBT_SETFOCUS, hook },
585     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
586     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
587     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
588     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
589     { WM_SYNCPAINT, sent|wparam|optional, 4 },
590     { WM_NCPAINT, sent|wparam|optional, 1 },
591     { WM_ERASEBKGND, sent|optional },
592     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
593     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
594     { 0 }
595 };
596 /* CreateWindow(WS_VISIBLE) for popup window */
597 static const struct message WmCreatePopupSeq[] = {
598     { HCBT_CREATEWND, hook },
599     { WM_NCCREATE, sent },
600     { WM_NCCALCSIZE, sent|wparam, 0 },
601     { WM_CREATE, sent },
602     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
603     { WM_SIZE, sent|wparam, SIZE_RESTORED },
604     { WM_MOVE, sent },
605     { WM_SHOWWINDOW, sent|wparam, 1 },
606     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
607     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
608     { HCBT_ACTIVATE, hook },
609     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
610     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
611     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
612     { WM_NCPAINT, sent|wparam|optional, 1 },
613     { WM_ERASEBKGND, sent|optional },
614     { WM_ACTIVATEAPP, sent|wparam, 1 },
615     { WM_NCACTIVATE, sent|wparam, 1 },
616     { WM_ACTIVATE, sent|wparam, 1 },
617     { HCBT_SETFOCUS, hook },
618     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
619     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
620     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
621     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
622     { WM_SYNCPAINT, sent|wparam|optional, 4 },
623     { WM_NCPAINT, sent|wparam|optional, 1 },
624     { WM_ERASEBKGND, sent|optional },
625     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
626     { 0 }
627 };
628 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
629 static const struct message WmShowVisMaxPopupSeq[] = {
630     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
631     { WM_GETMINMAXINFO, sent },
632     { WM_GETTEXT, sent|optional },
633     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
634     { WM_NCCALCSIZE, sent|wparam, TRUE },
635     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
636     { WM_NCPAINT, sent|wparam|optional, 1 },
637     { WM_ERASEBKGND, sent|optional },
638     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
639     { WM_MOVE, sent|defwinproc },
640     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
641     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
642     { 0 }
643 };
644 /* CreateWindow (for a child popup window, not initially visible) */
645 static const struct message WmCreateChildPopupSeq[] = {
646     { HCBT_CREATEWND, hook },
647     { WM_NCCREATE, sent }, 
648     { WM_NCCALCSIZE, sent|wparam, 0 },
649     { WM_CREATE, sent },
650     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
651     { WM_SIZE, sent|wparam, SIZE_RESTORED },
652     { WM_MOVE, sent },
653     { 0 }
654 };
655 /* CreateWindow (for a popup window, not initially visible,
656  * which sets WS_VISIBLE in WM_CREATE handler)
657  */
658 static const struct message WmCreateInvisiblePopupSeq[] = {
659     { HCBT_CREATEWND, hook },
660     { WM_NCCREATE, sent }, 
661     { WM_NCCALCSIZE, sent|wparam, 0 },
662     { WM_CREATE, sent },
663     { WM_STYLECHANGING, sent },
664     { WM_STYLECHANGED, sent },
665     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
666     { WM_SIZE, sent|wparam, SIZE_RESTORED },
667     { WM_MOVE, sent },
668     { 0 }
669 };
670 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
671  * for a popup window with WS_VISIBLE style set
672  */
673 static const struct message WmShowVisiblePopupSeq_2[] = {
674     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
675     { 0 }
676 };
677 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
678  * for a popup window with WS_VISIBLE style set
679  */
680 static const struct message WmShowVisiblePopupSeq_3[] = {
681     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
682     { HCBT_ACTIVATE, hook },
683     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
684     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
685     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
686     { WM_NCACTIVATE, sent|wparam, 1 },
687     { WM_ACTIVATE, sent|wparam, 1 },
688     { HCBT_SETFOCUS, hook },
689     { WM_KILLFOCUS, sent|parent },
690     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
691     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
692     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
693     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
694     { WM_SETFOCUS, sent|defwinproc },
695     { 0 }
696 };
697 /* CreateWindow (for child window, not initially visible) */
698 static const struct message WmCreateChildSeq[] = {
699     { HCBT_CREATEWND, hook },
700     { WM_NCCREATE, sent }, 
701     /* child is inserted into parent's child list after WM_NCCREATE returns */
702     { WM_NCCALCSIZE, sent|wparam, 0 },
703     { WM_CREATE, sent },
704     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
705     { WM_SIZE, sent|wparam, SIZE_RESTORED },
706     { WM_MOVE, sent },
707     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
708     { 0 }
709 };
710 /* CreateWindow (for maximized child window, not initially visible) */
711 static const struct message WmCreateMaximizedChildSeq[] = {
712     { HCBT_CREATEWND, hook },
713     { WM_NCCREATE, sent }, 
714     { WM_NCCALCSIZE, sent|wparam, 0 },
715     { WM_CREATE, sent },
716     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
717     { WM_SIZE, sent|wparam, SIZE_RESTORED },
718     { WM_MOVE, sent },
719     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
720     { WM_GETMINMAXINFO, sent },
721     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
722     { WM_NCCALCSIZE, sent|wparam, 1 },
723     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
724     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
725     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
726     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
727     { 0 }
728 };
729 /* CreateWindow (for a child window, initially visible) */
730 static const struct message WmCreateVisibleChildSeq[] = {
731     { HCBT_CREATEWND, hook },
732     { WM_NCCREATE, sent }, 
733     /* child is inserted into parent's child list after WM_NCCREATE returns */
734     { WM_NCCALCSIZE, sent|wparam, 0 },
735     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
736     { WM_CREATE, sent },
737     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
738     { WM_SIZE, sent|wparam, SIZE_RESTORED },
739     { WM_MOVE, sent },
740     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
741     { WM_SHOWWINDOW, sent|wparam, 1 },
742     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
743     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
744     { WM_ERASEBKGND, sent|parent|optional },
745     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
746     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
747     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
748     { 0 }
749 };
750 /* ShowWindow(SW_SHOW) for a not visible child window */
751 static const struct message WmShowChildSeq[] = {
752     { WM_SHOWWINDOW, sent|wparam, 1 },
753     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
754     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
755     { WM_ERASEBKGND, sent|parent|optional },
756     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
757     { 0 }
758 };
759 /* ShowWindow(SW_HIDE) for a visible child window */
760 static const struct message WmHideChildSeq[] = {
761     { WM_SHOWWINDOW, sent|wparam, 0 },
762     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
763     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
764     { WM_ERASEBKGND, sent|parent|optional },
765     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
766     { 0 }
767 };
768 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
769 static const struct message WmHideChildSeq2[] = {
770     { WM_SHOWWINDOW, sent|wparam, 0 },
771     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
772     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
773     { WM_ERASEBKGND, sent|parent },
774     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
775     { 0 }
776 };
777 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
778  * for a not visible child window
779  */
780 static const struct message WmShowChildSeq_2[] = {
781     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
782     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
783     { WM_CHILDACTIVATE, sent },
784     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
785     { 0 }
786 };
787 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
788  * for a not visible child window
789  */
790 static const struct message WmShowChildSeq_3[] = {
791     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
792     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
793     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
794     { 0 }
795 };
796 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
797  * for a visible child window with a caption
798  */
799 static const struct message WmShowChildSeq_4[] = {
800     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
801     { WM_CHILDACTIVATE, sent },
802     { 0 }
803 };
804 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
805 static const struct message WmShowChildInvisibleParentSeq_1[] = {
806     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
807     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
808     { WM_NCCALCSIZE, sent|wparam, 1 },
809     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
810     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
811     { WM_MOVE, sent|defwinproc },
812     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
813     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
814     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
815     /* FIXME: Wine creates an icon/title window while Windows doesn't */
816     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
817     { WM_GETTEXT, sent|optional },
818     { 0 }
819 };
820 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
821 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
822     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
823     { 0 }
824 };
825 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
826 static const struct message WmShowChildInvisibleParentSeq_2[] = {
827     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
828     { WM_GETMINMAXINFO, sent },
829     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
830     { WM_NCCALCSIZE, sent|wparam, 1 },
831     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
832     { WM_CHILDACTIVATE, sent },
833     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
834     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
835     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
836     { 0 }
837 };
838 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
839 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
840     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
841     { 0 }
842 };
843 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
844 static const struct message WmShowChildInvisibleParentSeq_3[] = {
845     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
846     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
847     { WM_NCCALCSIZE, sent|wparam, 1 },
848     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
849     { WM_CHILDACTIVATE, sent },
850     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
851     { WM_MOVE, sent|defwinproc },
852     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
853     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
854     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
855     /* FIXME: Wine creates an icon/title window while Windows doesn't */
856     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
857     { WM_GETTEXT, sent|optional },
858     { 0 }
859 };
860 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
861 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
862     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
863     { 0 }
864 };
865 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
866 static const struct message WmShowChildInvisibleParentSeq_4[] = {
867     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
868     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
869     { WM_NCCALCSIZE, sent|wparam, 1 },
870     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
871     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|0x8000 },
872     { WM_MOVE, sent|defwinproc },
873     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
874     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
875     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
876     /* FIXME: Wine creates an icon/title window while Windows doesn't */
877     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
878     { WM_GETTEXT, sent|optional },
879     { 0 }
880 };
881 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
882 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
883     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
884     { 0 }
885 };
886 /* ShowWindow(SW_SHOW) for child with invisible parent */
887 static const struct message WmShowChildInvisibleParentSeq_5[] = {
888     { WM_SHOWWINDOW, sent|wparam, 1 },
889     { 0 }
890 };
891 /* ShowWindow(SW_HIDE) for child with invisible parent */
892 static const struct message WmHideChildInvisibleParentSeq[] = {
893     { WM_SHOWWINDOW, sent|wparam, 0 },
894     { 0 }
895 };
896 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
897 static const struct message WmShowChildInvisibleParentSeq_6[] = {
898     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
899     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
900     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
901     { 0 }
902 };
903 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
904 static const struct message WmHideChildInvisibleParentSeq_2[] = {
905     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
906     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
907     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
908     { 0 }
909 };
910 /* DestroyWindow for a visible child window */
911 static const struct message WmDestroyChildSeq[] = {
912     { HCBT_DESTROYWND, hook },
913     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
914     { WM_SHOWWINDOW, sent|wparam, 0 },
915     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
916     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
917     { WM_ERASEBKGND, sent|parent|optional },
918     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
919     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
920     { WM_KILLFOCUS, sent },
921     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
922     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
923     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
924     { WM_SETFOCUS, sent|parent },
925     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
926     { WM_DESTROY, sent },
927     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
928     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
929     { WM_NCDESTROY, sent },
930     { 0 }
931 };
932 /* DestroyWindow for a visible child window with invisible parent */
933 static const struct message WmDestroyInvisibleChildSeq[] = {
934     { HCBT_DESTROYWND, hook },
935     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
936     { WM_SHOWWINDOW, sent|wparam, 0 },
937     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
938     { WM_DESTROY, sent },
939     { WM_NCDESTROY, sent },
940     { 0 }
941 };
942 /* Moving the mouse in nonclient area */
943 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
944     { WM_NCHITTEST, sent },
945     { WM_SETCURSOR, sent },
946     { WM_NCMOUSEMOVE, posted },
947     { 0 }
948 };
949 /* Moving the mouse in client area */
950 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
951     { WM_NCHITTEST, sent },
952     { WM_SETCURSOR, sent },
953     { WM_MOUSEMOVE, posted },
954     { 0 }
955 };
956 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
957 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
958     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
959     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
960     { WM_GETMINMAXINFO, sent|defwinproc },
961     { WM_ENTERSIZEMOVE, sent|defwinproc },
962     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
963     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
964     { WM_MOVE, sent|defwinproc },
965     { WM_EXITSIZEMOVE, sent|defwinproc },
966     { 0 }
967 };
968 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
969 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
970     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
971     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
972     { WM_GETMINMAXINFO, sent|defwinproc },
973     { WM_ENTERSIZEMOVE, sent|defwinproc },
974     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
975     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
976     { WM_GETMINMAXINFO, sent|defwinproc },
977     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
978     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
979     { WM_GETTEXT, sent|defwinproc },
980     { WM_ERASEBKGND, sent|defwinproc },
981     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
982     { WM_MOVE, sent|defwinproc },
983     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
984     { WM_EXITSIZEMOVE, sent|defwinproc },
985     { 0 }
986 };
987 /* Resizing child window with MoveWindow (32) */
988 static const struct message WmResizingChildWithMoveWindowSeq[] = {
989     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
990     { WM_NCCALCSIZE, sent|wparam, 1 },
991     { WM_ERASEBKGND, sent|parent|optional },
992     { WM_ERASEBKGND, sent|optional },
993     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
994     { WM_MOVE, sent|defwinproc },
995     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
996     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
997     { 0 }
998 };
999 /* Clicking on inactive button */
1000 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1001     { WM_NCHITTEST, sent },
1002     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1003     { WM_MOUSEACTIVATE, sent },
1004     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1005     { WM_SETCURSOR, sent },
1006     { WM_SETCURSOR, sent|parent|defwinproc },
1007     { WM_LBUTTONDOWN, posted },
1008     { WM_KILLFOCUS, posted|parent },
1009     { WM_SETFOCUS, posted },
1010     { WM_CTLCOLORBTN, posted|parent },
1011     { BM_SETSTATE, posted },
1012     { WM_CTLCOLORBTN, posted|parent },
1013     { WM_LBUTTONUP, posted },
1014     { BM_SETSTATE, posted },
1015     { WM_CTLCOLORBTN, posted|parent },
1016     { WM_COMMAND, posted|parent },
1017     { 0 }
1018 };
1019 /* Reparenting a button (16/32) */
1020 /* The last child (button) reparented gets topmost for its new parent. */
1021 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1022     { WM_SHOWWINDOW, sent|wparam, 0 },
1023     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1024     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1025     { WM_ERASEBKGND, sent|parent },
1026     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1027     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1028     { WM_CHILDACTIVATE, sent },
1029     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1030     { WM_MOVE, sent|defwinproc },
1031     { WM_SHOWWINDOW, sent|wparam, 1 },
1032     { 0 }
1033 };
1034 /* Creation of a custom dialog (32) */
1035 static const struct message WmCreateCustomDialogSeq[] = {
1036     { HCBT_CREATEWND, hook },
1037     { WM_GETMINMAXINFO, sent },
1038     { WM_NCCREATE, sent },
1039     { WM_NCCALCSIZE, sent|wparam, 0 },
1040     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1041     { WM_CREATE, sent },
1042     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1043     { WM_SHOWWINDOW, sent|wparam, 1 },
1044     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1045     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1046     { HCBT_ACTIVATE, hook },
1047     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1048
1049
1050     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1051
1052     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1053
1054     { WM_NCACTIVATE, sent|wparam, 1 },
1055     { WM_GETTEXT, sent|optional|defwinproc },
1056     { WM_GETTEXT, sent|optional|defwinproc },
1057     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1058     { WM_ACTIVATE, sent|wparam, 1 },
1059     { WM_KILLFOCUS, sent|parent },
1060     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1061     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1062     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1063     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1064     { WM_SETFOCUS, sent },
1065     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1066     { WM_NCPAINT, sent|wparam, 1 },
1067     { WM_GETTEXT, sent|optional|defwinproc },
1068     { WM_GETTEXT, sent|optional|defwinproc },
1069     { WM_ERASEBKGND, sent },
1070     { WM_CTLCOLORDLG, sent|defwinproc },
1071     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1072     { WM_GETTEXT, sent|optional },
1073     { WM_GETTEXT, sent|optional },
1074     { WM_NCCALCSIZE, sent|optional },
1075     { WM_NCPAINT, sent|optional },
1076     { WM_GETTEXT, sent|optional|defwinproc },
1077     { WM_GETTEXT, sent|optional|defwinproc },
1078     { WM_ERASEBKGND, sent|optional },
1079     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1080     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1081     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1082     { WM_MOVE, sent },
1083     { 0 }
1084 };
1085 /* Calling EndDialog for a custom dialog (32) */
1086 static const struct message WmEndCustomDialogSeq[] = {
1087     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1088     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1089     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1090     { WM_GETTEXT, sent|optional },
1091     { HCBT_ACTIVATE, hook },
1092     { WM_NCACTIVATE, sent|wparam, 0 },
1093     { WM_GETTEXT, sent|optional|defwinproc },
1094     { WM_GETTEXT, sent|optional|defwinproc },
1095     { WM_ACTIVATE, sent|wparam, 0 },
1096     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1097     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1098     { HCBT_SETFOCUS, hook },
1099     { WM_KILLFOCUS, sent },
1100     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1101     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1102     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1103     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1104     { WM_SETFOCUS, sent|parent|defwinproc },
1105     { 0 }
1106 };
1107 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1108 static const struct message WmShowCustomDialogSeq[] = {
1109     { WM_SHOWWINDOW, sent|wparam, 1 },
1110     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1111     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1112     { HCBT_ACTIVATE, hook },
1113     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1114
1115     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1116
1117     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1118     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1119     { WM_NCACTIVATE, sent|wparam, 1 },
1120     { WM_ACTIVATE, sent|wparam, 1 },
1121
1122     { WM_KILLFOCUS, sent|parent },
1123     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1124     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1125     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1126     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1127     { WM_SETFOCUS, sent },
1128     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1129     { WM_NCPAINT, sent|wparam, 1 },
1130     { WM_ERASEBKGND, sent },
1131     { WM_CTLCOLORDLG, sent|defwinproc },
1132     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1133     { 0 }
1134 };
1135 /* Creation and destruction of a modal dialog (32) */
1136 static const struct message WmModalDialogSeq[] = {
1137     { WM_CANCELMODE, sent|parent },
1138     { HCBT_SETFOCUS, hook },
1139     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1140     { WM_KILLFOCUS, sent|parent },
1141     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1142     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1143     { WM_ENABLE, sent|parent|wparam, 0 },
1144     { HCBT_CREATEWND, hook },
1145     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1146     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1147     { WM_SETFONT, sent },
1148     { WM_INITDIALOG, sent },
1149     { WM_CHANGEUISTATE, sent|optional },
1150     { WM_UPDATEUISTATE, sent|optional },
1151     { WM_SHOWWINDOW, sent },
1152     { HCBT_ACTIVATE, hook },
1153     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1154     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1156     { WM_NCACTIVATE, sent|wparam, 1 },
1157     { WM_GETTEXT, sent|optional },
1158     { WM_ACTIVATE, sent|wparam, 1 },
1159     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1160     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1161     { WM_NCPAINT, sent },
1162     { WM_GETTEXT, sent|optional },
1163     { WM_ERASEBKGND, sent },
1164     { WM_CTLCOLORDLG, sent },
1165     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1166     { WM_GETTEXT, sent|optional },
1167     { WM_NCCALCSIZE, sent|optional },
1168     { WM_NCPAINT, sent|optional },
1169     { WM_GETTEXT, sent|optional },
1170     { WM_ERASEBKGND, sent|optional },
1171     { WM_CTLCOLORDLG, sent|optional },
1172     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1173     { WM_PAINT, sent|optional },
1174     { WM_CTLCOLORBTN, sent },
1175     { WM_ENTERIDLE, sent|parent|optional },
1176     { WM_ENTERIDLE, sent|parent|optional },
1177     { WM_ENTERIDLE, sent|parent|optional },
1178     { WM_ENTERIDLE, sent|parent|optional },
1179     { WM_ENTERIDLE, sent|parent|optional },
1180     { WM_ENTERIDLE, sent|parent|optional },
1181     { WM_ENTERIDLE, sent|parent|optional },
1182     { WM_ENTERIDLE, sent|parent|optional },
1183     { WM_ENTERIDLE, sent|parent|optional },
1184     { WM_ENTERIDLE, sent|parent|optional },
1185     { WM_ENTERIDLE, sent|parent|optional },
1186     { WM_ENTERIDLE, sent|parent|optional },
1187     { WM_ENTERIDLE, sent|parent|optional },
1188     { WM_ENTERIDLE, sent|parent|optional },
1189     { WM_ENTERIDLE, sent|parent|optional },
1190     { WM_ENTERIDLE, sent|parent|optional },
1191     { WM_ENTERIDLE, sent|parent|optional },
1192     { WM_ENTERIDLE, sent|parent|optional },
1193     { WM_ENTERIDLE, sent|parent|optional },
1194     { WM_ENTERIDLE, sent|parent|optional },
1195     { WM_TIMER, sent },
1196     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1197     { WM_ENABLE, sent|parent|wparam, 1 },
1198     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1199     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1200     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1201     { WM_GETTEXT, sent|optional },
1202     { HCBT_ACTIVATE, hook },
1203     { WM_NCACTIVATE, sent|wparam, 0 },
1204     { WM_GETTEXT, sent|optional },
1205     { WM_ACTIVATE, sent|wparam, 0 },
1206     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1207     { WM_WINDOWPOSCHANGING, sent|optional },
1208     { HCBT_SETFOCUS, hook },
1209     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1210     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1211     { WM_SETFOCUS, sent|parent|defwinproc },
1212     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1213     { HCBT_DESTROYWND, hook },
1214     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1215     { WM_DESTROY, sent },
1216     { WM_NCDESTROY, sent },
1217     { 0 }
1218 };
1219 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1220 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1221     /* (inside dialog proc, handling WM_INITDIALOG) */
1222     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1223     { WM_NCCALCSIZE, sent },
1224     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1225     { WM_GETTEXT, sent|defwinproc },
1226     { WM_ACTIVATE, sent|parent|wparam, 0 },
1227     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1228     { WM_WINDOWPOSCHANGING, sent|parent },
1229     { WM_NCACTIVATE, sent|wparam, 1 },
1230     { WM_ACTIVATE, sent|wparam, 1 },
1231     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1232     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1233     /* (setting focus) */
1234     { WM_SHOWWINDOW, sent|wparam, 1 },
1235     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1236     { WM_NCPAINT, sent },
1237     { WM_GETTEXT, sent|defwinproc },
1238     { WM_ERASEBKGND, sent },
1239     { WM_CTLCOLORDLG, sent|defwinproc },
1240     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1241     { WM_PAINT, sent },
1242     /* (bunch of WM_CTLCOLOR* for each control) */
1243     { WM_PAINT, sent|parent },
1244     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1245     { WM_SETCURSOR, sent|parent },
1246     { 0 }
1247 };
1248 /* SetMenu for NonVisible windows with size change*/
1249 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1250     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1251     { WM_NCCALCSIZE, sent|wparam, 1 },
1252     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1253     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1254     { WM_MOVE, sent|defwinproc },
1255     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1256     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1257     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1258     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1259     { WM_GETTEXT, sent|optional },
1260     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1261     { 0 }
1262 };
1263 /* SetMenu for NonVisible windows with no size change */
1264 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1265     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1266     { WM_NCCALCSIZE, sent|wparam, 1 },
1267     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1268     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1269     { 0 }
1270 };
1271 /* SetMenu for Visible windows with size change */
1272 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1273     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1274     { WM_NCCALCSIZE, sent|wparam, 1 },
1275     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1276     { WM_NCPAINT, sent }, /* wparam != 1 */
1277     { WM_GETTEXT, sent|defwinproc|optional },
1278     { WM_ERASEBKGND, sent|optional },
1279     { WM_ACTIVATE, sent|optional },
1280     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1281     { WM_MOVE, sent|defwinproc },
1282     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1283     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1284     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1285     { WM_ERASEBKGND, sent|optional },
1286     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1287     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1288     { 0 }
1289 };
1290 /* SetMenu for Visible windows with no size change */
1291 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1292     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1293     { WM_NCCALCSIZE, sent|wparam, 1 },
1294     { WM_NCPAINT, sent }, /* wparam != 1 */
1295     { WM_GETTEXT, sent|defwinproc|optional },
1296     { WM_ERASEBKGND, sent|optional },
1297     { WM_ACTIVATE, sent|optional },
1298     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1299     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1300     { 0 }
1301 };
1302 /* DrawMenuBar for a visible window */
1303 static const struct message WmDrawMenuBarSeq[] =
1304 {
1305     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1306     { WM_NCCALCSIZE, sent|wparam, 1 },
1307     { WM_NCPAINT, sent }, /* wparam != 1 */
1308     { WM_GETTEXT, sent|defwinproc|optional },
1309     { WM_ERASEBKGND, sent|optional },
1310     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1311     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1312     { 0 }
1313 };
1314
1315 static const struct message WmSetRedrawFalseSeq[] =
1316 {
1317     { WM_SETREDRAW, sent|wparam, 0 },
1318     { 0 }
1319 };
1320
1321 static const struct message WmSetRedrawTrueSeq[] =
1322 {
1323     { WM_SETREDRAW, sent|wparam, 1 },
1324     { 0 }
1325 };
1326
1327 static const struct message WmEnableWindowSeq_1[] =
1328 {
1329     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1330     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1331     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1332     { 0 }
1333 };
1334
1335 static const struct message WmEnableWindowSeq_2[] =
1336 {
1337     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1338     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1339     { 0 }
1340 };
1341
1342 static const struct message WmGetScrollRangeSeq[] =
1343 {
1344     { SBM_GETRANGE, sent },
1345     { 0 }
1346 };
1347 static const struct message WmGetScrollInfoSeq[] =
1348 {
1349     { SBM_GETSCROLLINFO, sent },
1350     { 0 }
1351 };
1352 static const struct message WmSetScrollRangeSeq[] =
1353 {
1354     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1355        sends SBM_SETSCROLLINFO.
1356      */
1357     { SBM_SETSCROLLINFO, sent },
1358     { 0 }
1359 };
1360 /* SetScrollRange for a window without a non-client area */
1361 static const struct message WmSetScrollRangeHSeq_empty[] =
1362 {
1363     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1364     { 0 }
1365 };
1366 static const struct message WmSetScrollRangeVSeq_empty[] =
1367 {
1368     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1369     { 0 }
1370 };
1371 static const struct message WmSetScrollRangeHVSeq[] =
1372 {
1373     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1374     { WM_NCCALCSIZE, sent|wparam, 1 },
1375     { WM_GETTEXT, sent|defwinproc|optional },
1376     { WM_ERASEBKGND, sent|optional },
1377     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1378     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1379     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1380     { 0 }
1381 };
1382 /* SetScrollRange for a window with a non-client area */
1383 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1384 {
1385     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1386     { WM_NCCALCSIZE, sent|wparam, 1 },
1387     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1388     { WM_NCPAINT, sent|optional },
1389     { WM_GETTEXT, sent|defwinproc|optional },
1390     { WM_GETTEXT, sent|defwinproc|optional },
1391     { WM_ERASEBKGND, sent|optional },
1392     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1393     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1394     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1395     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1396     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1397     { WM_GETTEXT, sent|optional },
1398     { WM_GETTEXT, sent|optional },
1399     { WM_GETTEXT, sent|optional },
1400     { WM_GETTEXT, sent|optional },
1401     { 0 }
1402 };
1403 /* test if we receive the right sequence of messages */
1404 /* after calling ShowWindow( SW_SHOWNA) */
1405 static const struct message WmSHOWNAChildInvisParInvis[] = {
1406     { WM_SHOWWINDOW, sent|wparam, 1 },
1407     { 0 }
1408 };
1409 static const struct message WmSHOWNAChildVisParInvis[] = {
1410     { WM_SHOWWINDOW, sent|wparam, 1 },
1411     { 0 }
1412 };
1413 static const struct message WmSHOWNAChildVisParVis[] = {
1414     { WM_SHOWWINDOW, sent|wparam, 1 },
1415     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1416     { 0 }
1417 };
1418 static const struct message WmSHOWNAChildInvisParVis[] = {
1419     { WM_SHOWWINDOW, sent|wparam, 1 },
1420     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1421     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1422     { WM_ERASEBKGND, sent|optional },
1423     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1424     { 0 }
1425 };
1426 static const struct message WmSHOWNATopVisible[] = {
1427     { WM_SHOWWINDOW, sent|wparam, 1 },
1428     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1429     { 0 }
1430 };
1431 static const struct message WmSHOWNATopInvisible[] = {
1432     { WM_SHOWWINDOW, sent|wparam, 1 },
1433     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1434     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1435     { WM_NCPAINT, sent|wparam, 1 },
1436     { WM_GETTEXT, sent|defwinproc|optional },
1437     { WM_ERASEBKGND, sent|optional },
1438     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1439     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1440     { WM_NCPAINT, sent|wparam|optional, 1 },
1441     { WM_ERASEBKGND, sent|optional },
1442     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1443     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1444     { WM_MOVE, sent },
1445     { 0 }
1446 };
1447
1448 static int after_end_dialog, test_def_id;
1449 static int sequence_cnt, sequence_size;
1450 static struct message* sequence;
1451 static int log_all_parent_messages;
1452
1453 /* user32 functions */
1454 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1455 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1456 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1457 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1458 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1459 /* kernel32 functions */
1460 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1461
1462 static void init_procs(void)
1463 {
1464     HMODULE user32 = GetModuleHandleA("user32.dll");
1465     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1466
1467 #define GET_PROC(dll, func) \
1468     p ## func = (void*)GetProcAddress(dll, #func); \
1469     if(!p ## func) { \
1470       trace("GetProcAddress(%s) failed\n", #func); \
1471     }
1472
1473     GET_PROC(user32, GetAncestor)
1474     GET_PROC(user32, NotifyWinEvent)
1475     GET_PROC(user32, SetWinEventHook)
1476     GET_PROC(user32, TrackMouseEvent)
1477     GET_PROC(user32, UnhookWinEvent)
1478
1479     GET_PROC(kernel32, GetCPInfoExA)
1480
1481 #undef GET_PROC
1482 }
1483
1484 static void add_message(const struct message *msg)
1485 {
1486     if (!sequence) 
1487     {
1488         sequence_size = 10;
1489         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1490     }
1491     if (sequence_cnt == sequence_size) 
1492     {
1493         sequence_size *= 2;
1494         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1495     }
1496     assert(sequence);
1497
1498     sequence[sequence_cnt].message = msg->message;
1499     sequence[sequence_cnt].flags = msg->flags;
1500     sequence[sequence_cnt].wParam = msg->wParam;
1501     sequence[sequence_cnt].lParam = msg->lParam;
1502
1503     sequence_cnt++;
1504 }
1505
1506 /* try to make sure pending X events have been processed before continuing */
1507 static void flush_events(void)
1508 {
1509     MSG msg;
1510     int diff = 100;
1511     DWORD time = GetTickCount() + diff;
1512
1513     while (diff > 0)
1514     {
1515         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(10,diff), QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1516         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1517         diff = time - GetTickCount();
1518     }
1519 }
1520
1521 static void flush_sequence(void)
1522 {
1523     HeapFree(GetProcessHeap(), 0, sequence);
1524     sequence = 0;
1525     sequence_cnt = sequence_size = 0;
1526 }
1527
1528 #define ok_sequence( exp, contx, todo) \
1529         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1530
1531
1532 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1533         const char *file, int line)
1534 {
1535     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1536     const struct message *actual;
1537     int failcount = 0;
1538     
1539     add_message(&end_of_sequence);
1540
1541     actual = sequence;
1542
1543     while (expected->message && actual->message)
1544     {
1545         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1546
1547         if (expected->message == actual->message)
1548         {
1549             if (expected->flags & wparam)
1550             {
1551                 if (expected->wParam != actual->wParam && todo)
1552                 {
1553                     todo_wine {
1554                         failcount ++;
1555                         ok_( file, line) (FALSE,
1556                             "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1557                             context, expected->message, expected->wParam, actual->wParam);
1558                     }
1559                 }
1560                 else
1561                 ok_( file, line) (expected->wParam == actual->wParam,
1562                      "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1563                      context, expected->message, expected->wParam, actual->wParam);
1564             }
1565             if (expected->flags & lparam)
1566             {
1567                 if (expected->lParam != actual->lParam && todo)
1568                 {
1569                     todo_wine {
1570                         failcount ++;
1571                         ok_( file, line) (FALSE,
1572                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1573                             context, expected->message, expected->lParam, actual->lParam);
1574                     }
1575                 }
1576                 else
1577                  ok_( file, line) (expected->lParam == actual->lParam,
1578                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1579                      context, expected->message, expected->lParam, actual->lParam);
1580             }
1581             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1582             {
1583                     todo_wine {
1584                         failcount ++;
1585                         ok_( file, line) (FALSE,
1586                             "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1587                             context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1588                     }
1589             }
1590             else
1591                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1592                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1593                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1594             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1595                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1596                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1597             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1598                 "%s: the msg 0x%04x should have been %s\n",
1599                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1600             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1601                 "%s: the msg 0x%04x was expected in %s\n",
1602                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1603             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1604                 "%s: the msg 0x%04x should have been sent by a hook\n",
1605                 context, expected->message);
1606             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1607                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1608                 context, expected->message);
1609             expected++;
1610             actual++;
1611         }
1612         /* silently drop winevent messages if there is no support for them */
1613         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1614             expected++;
1615         else if (todo)
1616         {
1617             failcount++;
1618             todo_wine {
1619                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1620                     context, expected->message, actual->message);
1621             }
1622             flush_sequence();
1623             return;
1624         }
1625         else
1626         {
1627             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1628                 context, expected->message, actual->message);
1629             expected++;
1630             actual++;
1631         }
1632     }
1633
1634     /* skip all optional trailing messages */
1635     while (expected->message && ((expected->flags & optional) ||
1636             ((expected->flags & winevent_hook) && !hEvent_hook)))
1637         expected++;
1638
1639     if (todo)
1640     {
1641         todo_wine {
1642             if (expected->message || actual->message) {
1643                 failcount++;
1644                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1645                     context, expected->message, actual->message);
1646             }
1647         }
1648     }
1649     else
1650     {
1651         if (expected->message || actual->message)
1652             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1653                 context, expected->message, actual->message);
1654     }
1655     if( todo && !failcount) /* succeeded yet marked todo */
1656         todo_wine {
1657             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1658         }
1659
1660     flush_sequence();
1661 }
1662
1663 /******************************** MDI test **********************************/
1664
1665 /* CreateWindow for MDI frame window, initially visible */
1666 static const struct message WmCreateMDIframeSeq[] = {
1667     { HCBT_CREATEWND, hook },
1668     { WM_GETMINMAXINFO, sent },
1669     { WM_NCCREATE, sent },
1670     { WM_NCCALCSIZE, sent|wparam, 0 },
1671     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1672     { WM_CREATE, sent },
1673     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1674     { WM_SHOWWINDOW, sent|wparam, 1 },
1675     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1676     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1677     { HCBT_ACTIVATE, hook },
1678     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1679     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1680     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1681     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1682     { WM_NCACTIVATE, sent|wparam, 1 },
1683     { WM_GETTEXT, sent|defwinproc|optional },
1684     { WM_ACTIVATE, sent|wparam, 1 },
1685     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1686     { HCBT_SETFOCUS, hook },
1687     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1688     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1689     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1690     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1691     /* Win9x adds SWP_NOZORDER below */
1692     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1693     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1694     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1695     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1696     { WM_MOVE, sent },
1697     { 0 }
1698 };
1699 /* DestroyWindow for MDI frame window, initially visible */
1700 static const struct message WmDestroyMDIframeSeq[] = {
1701     { HCBT_DESTROYWND, hook },
1702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1703     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1704     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1705     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1706     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1707     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1708     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1709     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1710     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1711     { WM_DESTROY, sent },
1712     { WM_NCDESTROY, sent },
1713     { 0 }
1714 };
1715 /* CreateWindow for MDI client window, initially visible */
1716 static const struct message WmCreateMDIclientSeq[] = {
1717     { HCBT_CREATEWND, hook },
1718     { WM_NCCREATE, sent },
1719     { WM_NCCALCSIZE, sent|wparam, 0 },
1720     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1721     { WM_CREATE, sent },
1722     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1723     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1724     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1725     { WM_MOVE, sent },
1726     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1727     { WM_SHOWWINDOW, sent|wparam, 1 },
1728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1729     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1730     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1731     { 0 }
1732 };
1733 /* ShowWindow(SW_SHOW) for MDI client window */
1734 static const struct message WmShowMDIclientSeq[] = {
1735     { WM_SHOWWINDOW, sent|wparam, 1 },
1736     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1737     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1738     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1739     { 0 }
1740 };
1741 /* ShowWindow(SW_HIDE) for MDI client window */
1742 static const struct message WmHideMDIclientSeq[] = {
1743     { WM_SHOWWINDOW, sent|wparam, 0 },
1744     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1745     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1746     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1747     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1748     { 0 }
1749 };
1750 /* DestroyWindow for MDI client window, initially visible */
1751 static const struct message WmDestroyMDIclientSeq[] = {
1752     { HCBT_DESTROYWND, hook },
1753     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1754     { WM_SHOWWINDOW, sent|wparam, 0 },
1755     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1756     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1757     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1758     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1759     { WM_DESTROY, sent },
1760     { WM_NCDESTROY, sent },
1761     { 0 }
1762 };
1763 /* CreateWindow for MDI child window, initially visible */
1764 static const struct message WmCreateMDIchildVisibleSeq[] = {
1765     { HCBT_CREATEWND, hook },
1766     { WM_NCCREATE, sent }, 
1767     { WM_NCCALCSIZE, sent|wparam, 0 },
1768     { WM_CREATE, sent },
1769     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1770     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1771     { WM_MOVE, sent },
1772     /* Win2k sends wparam set to
1773      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1774      * while Win9x doesn't bother to set child window id according to
1775      * CLIENTCREATESTRUCT.idFirstChild
1776      */
1777     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1778     { WM_SHOWWINDOW, sent|wparam, 1 },
1779     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1780     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1781     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1782     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1783     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1784     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1785     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1786
1787     /* Win9x: message sequence terminates here. */
1788
1789     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1790     { HCBT_SETFOCUS, hook }, /* in MDI client */
1791     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1792     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1793     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1794     { WM_SETFOCUS, sent }, /* in MDI client */
1795     { HCBT_SETFOCUS, hook },
1796     { WM_KILLFOCUS, sent }, /* in MDI client */
1797     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1798     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1799     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1800     { WM_SETFOCUS, sent|defwinproc },
1801     { WM_MDIACTIVATE, sent|defwinproc },
1802     { 0 }
1803 };
1804 /* CreateWindow for MDI child window with invisible parent */
1805 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
1806     { HCBT_CREATEWND, hook },
1807     { WM_GETMINMAXINFO, sent },
1808     { WM_NCCREATE, sent }, 
1809     { WM_NCCALCSIZE, sent|wparam, 0 },
1810     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1811     { WM_CREATE, sent },
1812     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1813     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1814     { WM_MOVE, sent },
1815     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1816     { WM_SHOWWINDOW, sent|wparam, 1 },
1817     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
1818     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1819     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1820     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1821
1822     /* Win9x: message sequence terminates here. */
1823
1824     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1825     { HCBT_SETFOCUS, hook }, /* in MDI client */
1826     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1827     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1828     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1829     { WM_SETFOCUS, sent }, /* in MDI client */
1830     { HCBT_SETFOCUS, hook },
1831     { WM_KILLFOCUS, sent }, /* in MDI client */
1832     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1833     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1834     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1835     { WM_SETFOCUS, sent|defwinproc },
1836     { WM_MDIACTIVATE, sent|defwinproc },
1837     { 0 }
1838 };
1839 /* DestroyWindow for MDI child window, initially visible */
1840 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1841     { HCBT_DESTROYWND, hook },
1842     /* Win2k sends wparam set to
1843      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1844      * while Win9x doesn't bother to set child window id according to
1845      * CLIENTCREATESTRUCT.idFirstChild
1846      */
1847     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1848     { WM_SHOWWINDOW, sent|wparam, 0 },
1849     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1850     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1851     { WM_ERASEBKGND, sent|parent|optional },
1852     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1853
1854     /* { WM_DESTROY, sent }
1855      * Win9x: message sequence terminates here.
1856      */
1857
1858     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1859     { WM_KILLFOCUS, sent },
1860     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1861     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1862     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1863     { WM_SETFOCUS, sent }, /* in MDI client */
1864
1865     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1866     { WM_KILLFOCUS, sent }, /* in MDI client */
1867     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1868     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1869     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1870     { WM_SETFOCUS, sent }, /* in MDI client */
1871
1872     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1873
1874     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1875     { WM_KILLFOCUS, sent },
1876     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1877     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1878     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1879     { WM_SETFOCUS, sent }, /* in MDI client */
1880
1881     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1882     { WM_KILLFOCUS, sent }, /* in MDI client */
1883     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1884     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1885     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1886     { WM_SETFOCUS, sent }, /* in MDI client */
1887
1888     { WM_DESTROY, sent },
1889
1890     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1891     { WM_KILLFOCUS, sent },
1892     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1893     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1894     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1895     { WM_SETFOCUS, sent }, /* in MDI client */
1896
1897     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1898     { WM_KILLFOCUS, sent }, /* in MDI client */
1899     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1900     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1901     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1902     { WM_SETFOCUS, sent }, /* in MDI client */
1903
1904     { WM_NCDESTROY, sent },
1905     { 0 }
1906 };
1907 /* CreateWindow for MDI child window, initially invisible */
1908 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1909     { HCBT_CREATEWND, hook },
1910     { WM_NCCREATE, sent }, 
1911     { WM_NCCALCSIZE, sent|wparam, 0 },
1912     { WM_CREATE, sent },
1913     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1914     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1915     { WM_MOVE, sent },
1916     /* Win2k sends wparam set to
1917      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1918      * while Win9x doesn't bother to set child window id according to
1919      * CLIENTCREATESTRUCT.idFirstChild
1920      */
1921     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1922     { 0 }
1923 };
1924 /* DestroyWindow for MDI child window, initially invisible */
1925 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1926     { HCBT_DESTROYWND, hook },
1927     /* Win2k sends wparam set to
1928      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1929      * while Win9x doesn't bother to set child window id according to
1930      * CLIENTCREATESTRUCT.idFirstChild
1931      */
1932     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1933     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1934     { WM_DESTROY, sent },
1935     { WM_NCDESTROY, sent },
1936     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
1937     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
1938     { 0 }
1939 };
1940 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1941 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1942     { HCBT_CREATEWND, hook },
1943     { WM_NCCREATE, sent }, 
1944     { WM_NCCALCSIZE, sent|wparam, 0 },
1945     { WM_CREATE, sent },
1946     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1947     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1948     { WM_MOVE, sent },
1949     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1950     { WM_GETMINMAXINFO, sent },
1951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1952     { WM_NCCALCSIZE, sent|wparam, 1 },
1953     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1954     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1955      /* in MDI frame */
1956     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1957     { WM_NCCALCSIZE, sent|wparam, 1 },
1958     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1959     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1960     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1961     /* Win2k sends wparam set to
1962      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1963      * while Win9x doesn't bother to set child window id according to
1964      * CLIENTCREATESTRUCT.idFirstChild
1965      */
1966     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1967     { WM_SHOWWINDOW, sent|wparam, 1 },
1968     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1969     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1970     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1971     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1972     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1973     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1974     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1975
1976     /* Win9x: message sequence terminates here. */
1977
1978     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1979     { HCBT_SETFOCUS, hook }, /* in MDI client */
1980     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1981     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1982     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1983     { WM_SETFOCUS, sent }, /* in MDI client */
1984     { HCBT_SETFOCUS, hook },
1985     { WM_KILLFOCUS, sent }, /* in MDI client */
1986     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1987     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1988     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1989     { WM_SETFOCUS, sent|defwinproc },
1990     { WM_MDIACTIVATE, sent|defwinproc },
1991      /* in MDI frame */
1992     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1993     { WM_NCCALCSIZE, sent|wparam, 1 },
1994     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1995     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1996     { 0 }
1997 };
1998 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1999 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2000     /* restore the 1st MDI child */
2001     { WM_SETREDRAW, sent|wparam, 0 },
2002     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2003     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2004     { WM_NCCALCSIZE, sent|wparam, 1 },
2005     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2006     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2007     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2008      /* in MDI frame */
2009     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2010     { WM_NCCALCSIZE, sent|wparam, 1 },
2011     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2012     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2013     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2014     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2015     /* create the 2nd MDI child */
2016     { HCBT_CREATEWND, hook },
2017     { WM_NCCREATE, sent }, 
2018     { WM_NCCALCSIZE, sent|wparam, 0 },
2019     { WM_CREATE, sent },
2020     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2021     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2022     { WM_MOVE, sent },
2023     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2024     { WM_GETMINMAXINFO, sent },
2025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2026     { WM_NCCALCSIZE, sent|wparam, 1 },
2027     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2028     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2029     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2030      /* in MDI frame */
2031     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2032     { WM_NCCALCSIZE, sent|wparam, 1 },
2033     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2034     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2035     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
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     { WM_SHOWWINDOW, sent|wparam, 1 },
2043     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2044     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2046     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2047     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2048     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2049
2050     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2051     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2052
2053     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2054
2055     /* Win9x: message sequence terminates here. */
2056
2057     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2058     { HCBT_SETFOCUS, hook },
2059     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
2060     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2061     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2062     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2063     { WM_SETFOCUS, sent }, /* in MDI client */
2064     { HCBT_SETFOCUS, hook },
2065     { WM_KILLFOCUS, sent }, /* in MDI client */
2066     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2067     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2068     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2069     { WM_SETFOCUS, sent|defwinproc },
2070
2071     { WM_MDIACTIVATE, sent|defwinproc },
2072      /* in MDI frame */
2073     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2074     { WM_NCCALCSIZE, sent|wparam, 1 },
2075     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2076     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2077     { 0 }
2078 };
2079 /* WM_MDICREATE MDI child window, initially visible and maximized */
2080 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2081     { WM_MDICREATE, sent },
2082     { HCBT_CREATEWND, hook },
2083     { WM_NCCREATE, sent }, 
2084     { WM_NCCALCSIZE, sent|wparam, 0 },
2085     { WM_CREATE, sent },
2086     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2087     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2088     { WM_MOVE, sent },
2089     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2090     { WM_GETMINMAXINFO, sent },
2091     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2092     { WM_NCCALCSIZE, sent|wparam, 1 },
2093     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2094     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2095
2096      /* in MDI frame */
2097     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2098     { WM_NCCALCSIZE, sent|wparam, 1 },
2099     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2100     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2101     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2102
2103     /* Win2k sends wparam set to
2104      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2105      * while Win9x doesn't bother to set child window id according to
2106      * CLIENTCREATESTRUCT.idFirstChild
2107      */
2108     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2109     { WM_SHOWWINDOW, sent|wparam, 1 },
2110     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2111
2112     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2113
2114     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2115     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2116     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2117
2118     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2119     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2120
2121     /* Win9x: message sequence terminates here. */
2122
2123     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2124     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2125     { HCBT_SETFOCUS, hook }, /* in MDI client */
2126     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2127     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2128     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2129     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2130     { HCBT_SETFOCUS, hook|optional },
2131     { WM_KILLFOCUS, sent }, /* in MDI client */
2132     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2133     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2134     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2135     { WM_SETFOCUS, sent|defwinproc },
2136
2137     { WM_MDIACTIVATE, sent|defwinproc },
2138
2139      /* in MDI child */
2140     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2141     { WM_NCCALCSIZE, sent|wparam, 1 },
2142     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2143     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2144
2145      /* in MDI frame */
2146     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2147     { WM_NCCALCSIZE, sent|wparam, 1 },
2148     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2149     { WM_MOVE, sent|defwinproc },
2150     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2151
2152      /* in MDI client */
2153     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2154     { WM_NCCALCSIZE, sent|wparam, 1 },
2155     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2156     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2157
2158      /* in MDI child */
2159     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2160     { WM_NCCALCSIZE, sent|wparam, 1 },
2161     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2162     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2163
2164     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2165     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2166     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2167     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2168     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2169
2170     { 0 }
2171 };
2172 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2173 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2174     { HCBT_CREATEWND, hook },
2175     { WM_GETMINMAXINFO, sent },
2176     { WM_NCCREATE, sent }, 
2177     { WM_NCCALCSIZE, sent|wparam, 0 },
2178     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2179     { WM_CREATE, sent },
2180     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2181     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2182     { WM_MOVE, sent },
2183     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2184     { WM_GETMINMAXINFO, sent },
2185     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
2186     { WM_GETMINMAXINFO, sent|defwinproc },
2187     { WM_NCCALCSIZE, sent|wparam, 1 },
2188     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|0x8000 },
2189     { WM_MOVE, sent|defwinproc },
2190     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2191      /* in MDI frame */
2192     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2193     { WM_NCCALCSIZE, sent|wparam, 1 },
2194     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2195     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2196     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2197     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2198     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2199     /* Win2k sends wparam set to
2200      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2201      * while Win9x doesn't bother to set child window id according to
2202      * CLIENTCREATESTRUCT.idFirstChild
2203      */
2204     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2205     { 0 }
2206 };
2207 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2208 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2209     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2210     { HCBT_SYSCOMMAND, hook },
2211     { WM_CLOSE, sent|defwinproc },
2212     { WM_MDIDESTROY, sent }, /* in MDI client */
2213
2214     /* bring the 1st MDI child to top */
2215     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2216     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2217
2218     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2219
2220     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2221     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2222     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2223
2224     /* maximize the 1st MDI child */
2225     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2226     { WM_GETMINMAXINFO, sent|defwinproc },
2227     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
2228     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2229     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2230     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2231     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2232
2233     /* restore the 2nd MDI child */
2234     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2235     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2236     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2237     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2238
2239     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2240
2241     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2242     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2243
2244     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2245
2246     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2247      /* in MDI frame */
2248     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2249     { WM_NCCALCSIZE, sent|wparam, 1 },
2250     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2251     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2252     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2253
2254     /* bring the 1st MDI child to top */
2255     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2256     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2257     { HCBT_SETFOCUS, hook },
2258     { WM_KILLFOCUS, sent|defwinproc },
2259     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2260     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2261     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2262     { WM_SETFOCUS, sent }, /* in MDI client */
2263     { HCBT_SETFOCUS, hook },
2264     { WM_KILLFOCUS, sent }, /* in MDI client */
2265     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2266     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2267     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2268     { WM_SETFOCUS, sent|defwinproc },
2269     { WM_MDIACTIVATE, sent|defwinproc },
2270     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2271
2272     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2273     { WM_SHOWWINDOW, sent|wparam, 1 },
2274     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2275     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2276     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2277     { WM_MDIREFRESHMENU, sent },
2278
2279     { HCBT_DESTROYWND, hook },
2280     /* Win2k sends wparam set to
2281      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2282      * while Win9x doesn't bother to set child window id according to
2283      * CLIENTCREATESTRUCT.idFirstChild
2284      */
2285     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2286     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2287     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2288     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2289     { WM_ERASEBKGND, sent|parent|optional },
2290     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2291
2292     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2293     { WM_DESTROY, sent|defwinproc },
2294     { WM_NCDESTROY, sent|defwinproc },
2295     { 0 }
2296 };
2297 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2298 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2299     { WM_MDIDESTROY, sent }, /* in MDI client */
2300     { WM_SHOWWINDOW, sent|wparam, 0 },
2301     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2302     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2303     { WM_ERASEBKGND, sent|parent|optional },
2304     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2305
2306     { HCBT_SETFOCUS, hook },
2307     { WM_KILLFOCUS, sent },
2308     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2309     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2310     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2311     { WM_SETFOCUS, sent }, /* in MDI client */
2312     { HCBT_SETFOCUS, hook },
2313     { WM_KILLFOCUS, sent }, /* in MDI client */
2314     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2315     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2316     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2317     { WM_SETFOCUS, sent },
2318
2319      /* in MDI child */
2320     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2321     { WM_NCCALCSIZE, sent|wparam, 1 },
2322     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2323     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2324
2325      /* in MDI frame */
2326     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2327     { WM_NCCALCSIZE, sent|wparam, 1 },
2328     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2329     { WM_MOVE, sent|defwinproc },
2330     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2331
2332      /* in MDI client */
2333     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2334     { WM_NCCALCSIZE, sent|wparam, 1 },
2335     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2336     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2337
2338      /* in MDI child */
2339     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2340     { WM_NCCALCSIZE, sent|wparam, 1 },
2341     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2342     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2343
2344      /* in MDI child */
2345     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2346     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2347     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2348     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2349
2350      /* in MDI frame */
2351     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2352     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2353     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2354     { WM_MOVE, sent|defwinproc },
2355     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2356
2357      /* in MDI client */
2358     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2359     { WM_NCCALCSIZE, sent|wparam, 1 },
2360     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2361     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2362
2363      /* in MDI child */
2364     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2365     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2366     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2367     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2368     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2369     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2370
2371     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2372
2373     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2374     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2375     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2376     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2377     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2378
2379      /* in MDI frame */
2380     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2381     { WM_NCCALCSIZE, sent|wparam, 1 },
2382     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2383     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2384
2385     { WM_NCACTIVATE, sent|wparam, 0 },
2386     { WM_MDIACTIVATE, sent },
2387
2388     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2389     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2390     { WM_NCCALCSIZE, sent|wparam, 1 },
2391
2392     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2393
2394     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2395     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|0x8000 },
2396     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2397
2398      /* in MDI child */
2399     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2400     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2401     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2402     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2403
2404      /* in MDI frame */
2405     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2406     { WM_NCCALCSIZE, sent|wparam, 1 },
2407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2408     { WM_MOVE, sent|defwinproc },
2409     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2410
2411      /* in MDI client */
2412     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2413     { WM_NCCALCSIZE, sent|wparam, 1 },
2414     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2415     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2416     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2417     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2418     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2419     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2420     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2421
2422     { HCBT_SETFOCUS, hook },
2423     { WM_KILLFOCUS, sent },
2424     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2425     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2426     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2427     { WM_SETFOCUS, sent }, /* in MDI client */
2428
2429     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2430
2431     { HCBT_DESTROYWND, hook },
2432     /* Win2k sends wparam set to
2433      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2434      * while Win9x doesn't bother to set child window id according to
2435      * CLIENTCREATESTRUCT.idFirstChild
2436      */
2437     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2438
2439     { WM_SHOWWINDOW, sent|wparam, 0 },
2440     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2441     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2442     { WM_ERASEBKGND, sent|parent|optional },
2443     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2444
2445     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2446     { WM_DESTROY, sent },
2447     { WM_NCDESTROY, sent },
2448     { 0 }
2449 };
2450 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2451 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2452     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2453     { WM_GETMINMAXINFO, sent },
2454     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2455     { WM_NCCALCSIZE, sent|wparam, 1 },
2456     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2457     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2458
2459     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2460     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2461     { HCBT_SETFOCUS, hook },
2462     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2463     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2464     { WM_SETFOCUS, sent }, /* in MDI client */
2465     { HCBT_SETFOCUS, hook },
2466     { WM_KILLFOCUS, sent }, /* in MDI client */
2467     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2468     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2469     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2470     { WM_SETFOCUS, sent|defwinproc },
2471     { WM_MDIACTIVATE, sent|defwinproc },
2472     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2473     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2474      /* in MDI frame */
2475     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2476     { WM_NCCALCSIZE, sent|wparam, 1 },
2477     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2478     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2479     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2480     { 0 }
2481 };
2482 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2483 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2484     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2485     { WM_GETMINMAXINFO, sent },
2486     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2487     { WM_GETMINMAXINFO, sent|defwinproc },
2488     { WM_NCCALCSIZE, sent|wparam, 1 },
2489     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2490     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2491
2492     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2493     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2494     { HCBT_SETFOCUS, hook },
2495     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2496     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2497     { WM_SETFOCUS, sent }, /* in MDI client */
2498     { HCBT_SETFOCUS, hook },
2499     { WM_KILLFOCUS, sent }, /* in MDI client */
2500     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2501     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2502     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2503     { WM_SETFOCUS, sent|defwinproc },
2504     { WM_MDIACTIVATE, sent|defwinproc },
2505     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2506     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2507     { 0 }
2508 };
2509 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2510 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2511     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2512     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2513     { WM_GETMINMAXINFO, sent },
2514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2515     { WM_GETMINMAXINFO, sent|defwinproc },
2516     { WM_NCCALCSIZE, sent|wparam, 1 },
2517     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2518     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2519     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|0x8000 },
2520     { WM_MOVE, sent|defwinproc },
2521     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2522
2523     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2524     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2525     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2526     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2527     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2528     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2529      /* in MDI frame */
2530     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2531     { WM_NCCALCSIZE, sent|wparam, 1 },
2532     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2533     { WM_MOVE, sent|defwinproc },
2534     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2535     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2536      /* in MDI client */
2537     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2538     { WM_NCCALCSIZE, sent|wparam, 1 },
2539     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2540     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2541      /* in MDI child */
2542     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2543     { WM_GETMINMAXINFO, sent|defwinproc },
2544     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2545     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2546     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2547     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2548     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2549     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2550     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2551     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2552      /* in MDI frame */
2553     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2554     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2555     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2556     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2557     { 0 }
2558 };
2559 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2560 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2561     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2562     { WM_GETMINMAXINFO, sent },
2563     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2564     { WM_NCCALCSIZE, sent|wparam, 1 },
2565     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2566     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2567     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2568      /* in MDI frame */
2569     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2570     { WM_NCCALCSIZE, sent|wparam, 1 },
2571     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2572     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2573     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2574     { 0 }
2575 };
2576 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2577 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2578     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2580     { WM_NCCALCSIZE, sent|wparam, 1 },
2581     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2582     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2583     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2584      /* in MDI frame */
2585     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2586     { WM_NCCALCSIZE, sent|wparam, 1 },
2587     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2588     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2589     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2590     { 0 }
2591 };
2592 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2593 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2594     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2595     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2596     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
2597     { WM_NCCALCSIZE, sent|wparam, 1 },
2598     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2599     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2600     { WM_MOVE, sent|defwinproc },
2601     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2602     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2603     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2604     { HCBT_SETFOCUS, hook },
2605     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2606     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2607     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2608     { WM_SETFOCUS, sent },
2609     { 0 }
2610 };
2611 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2612 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2613     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2614     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|0x8000 },
2615     { WM_NCCALCSIZE, sent|wparam, 1 },
2616     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|0x8000 },
2617     { WM_MOVE, sent|defwinproc },
2618     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2619     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2620     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2621     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2622     /* FIXME: Wine creates an icon/title window while Windows doesn't */
2623     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2624     { 0 }
2625 };
2626 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2627 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2628     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2630     { WM_NCCALCSIZE, sent|wparam, 1 },
2631     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2632     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2633     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2634     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2635      /* in MDI frame */
2636     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2637     { WM_NCCALCSIZE, sent|wparam, 1 },
2638     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2639     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2640     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2641     { 0 }
2642 };
2643
2644 static HWND mdi_client;
2645 static WNDPROC old_mdi_client_proc;
2646
2647 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2648 {
2649     struct message msg;
2650
2651     /* do not log painting messages */
2652     if (message != WM_PAINT &&
2653         message != WM_NCPAINT &&
2654         message != WM_SYNCPAINT &&
2655         message != WM_ERASEBKGND &&
2656         message != WM_NCPAINT &&
2657         message != WM_NCHITTEST &&
2658         message != WM_GETTEXT &&
2659         message != WM_MDIGETACTIVE &&
2660         message != WM_GETICON &&
2661         message != WM_DEVICECHANGE)
2662     {
2663         trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2664
2665         switch (message)
2666         {
2667             case WM_WINDOWPOSCHANGING:
2668             case WM_WINDOWPOSCHANGED:
2669             {
2670                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2671
2672                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2673                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2674                       winpos->hwnd, winpos->hwndInsertAfter,
2675                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2676                 dump_winpos_flags(winpos->flags);
2677
2678                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2679                  * in the high word for internal purposes
2680                  */
2681                 wParam = winpos->flags & 0xffff;
2682                 /* We are not interested in the flags that don't match under XP and Win9x */
2683                 wParam &= ~(SWP_NOZORDER);
2684                 break;
2685             }
2686         }
2687
2688         msg.message = message;
2689         msg.flags = sent|wparam|lparam;
2690         msg.wParam = wParam;
2691         msg.lParam = lParam;
2692         add_message(&msg);
2693     }
2694
2695     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2696 }
2697
2698 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2699 {
2700     static long defwndproc_counter = 0;
2701     LRESULT ret;
2702     struct message msg;
2703
2704     /* do not log painting messages */
2705     if (message != WM_PAINT &&
2706         message != WM_NCPAINT &&
2707         message != WM_SYNCPAINT &&
2708         message != WM_ERASEBKGND &&
2709         message != WM_NCPAINT &&
2710         message != WM_NCHITTEST &&
2711         message != WM_GETTEXT &&
2712         message != WM_GETICON &&
2713         message != WM_DEVICECHANGE)
2714     {
2715         trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2716
2717         switch (message)
2718         {
2719             case WM_WINDOWPOSCHANGING:
2720             case WM_WINDOWPOSCHANGED:
2721             {
2722                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2723
2724                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2725                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2726                       winpos->hwnd, winpos->hwndInsertAfter,
2727                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2728                 dump_winpos_flags(winpos->flags);
2729
2730                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2731                  * in the high word for internal purposes
2732                  */
2733                 wParam = winpos->flags & 0xffff;
2734                 /* We are not interested in the flags that don't match under XP and Win9x */
2735                 wParam &= ~(SWP_NOZORDER);
2736                 break;
2737             }
2738
2739             case WM_MDIACTIVATE:
2740             {
2741                 HWND active, client = GetParent(hwnd);
2742
2743                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2744
2745                 if (hwnd == (HWND)lParam) /* if we are being activated */
2746                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2747                 else
2748                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2749                 break;
2750             }
2751         }
2752
2753         msg.message = message;
2754         msg.flags = sent|wparam|lparam;
2755         if (defwndproc_counter) msg.flags |= defwinproc;
2756         msg.wParam = wParam;
2757         msg.lParam = lParam;
2758         add_message(&msg);
2759     }
2760
2761     defwndproc_counter++;
2762     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2763     defwndproc_counter--;
2764
2765     return ret;
2766 }
2767
2768 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2769 {
2770     static long defwndproc_counter = 0;
2771     LRESULT ret;
2772     struct message msg;
2773
2774     /* do not log painting messages */
2775     if (message != WM_PAINT &&
2776         message != WM_NCPAINT &&
2777         message != WM_SYNCPAINT &&
2778         message != WM_ERASEBKGND &&
2779         message != WM_NCPAINT &&
2780         message != WM_NCHITTEST &&
2781         message != WM_GETTEXT &&
2782         message != WM_GETICON &&
2783         message != WM_DEVICECHANGE)
2784     {
2785         trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2786
2787         switch (message)
2788         {
2789             case WM_WINDOWPOSCHANGING:
2790             case WM_WINDOWPOSCHANGED:
2791             {
2792                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2793
2794                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2795                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2796                       winpos->hwnd, winpos->hwndInsertAfter,
2797                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2798                 dump_winpos_flags(winpos->flags);
2799
2800                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2801                  * in the high word for internal purposes
2802                  */
2803                 wParam = winpos->flags & 0xffff;
2804                 /* We are not interested in the flags that don't match under XP and Win9x */
2805                 wParam &= ~(SWP_NOZORDER);
2806                 break;
2807             }
2808         }
2809
2810         msg.message = message;
2811         msg.flags = sent|wparam|lparam;
2812         if (defwndproc_counter) msg.flags |= defwinproc;
2813         msg.wParam = wParam;
2814         msg.lParam = lParam;
2815         add_message(&msg);
2816     }
2817
2818     defwndproc_counter++;
2819     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2820     defwndproc_counter--;
2821
2822     return ret;
2823 }
2824
2825 static BOOL mdi_RegisterWindowClasses(void)
2826 {
2827     WNDCLASSA cls;
2828
2829     cls.style = 0;
2830     cls.lpfnWndProc = mdi_frame_wnd_proc;
2831     cls.cbClsExtra = 0;
2832     cls.cbWndExtra = 0;
2833     cls.hInstance = GetModuleHandleA(0);
2834     cls.hIcon = 0;
2835     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2836     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2837     cls.lpszMenuName = NULL;
2838     cls.lpszClassName = "MDI_frame_class";
2839     if (!RegisterClassA(&cls)) return FALSE;
2840
2841     cls.lpfnWndProc = mdi_child_wnd_proc;
2842     cls.lpszClassName = "MDI_child_class";
2843     if (!RegisterClassA(&cls)) return FALSE;
2844
2845     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2846     old_mdi_client_proc = cls.lpfnWndProc;
2847     cls.hInstance = GetModuleHandleA(0);
2848     cls.lpfnWndProc = mdi_client_hook_proc;
2849     cls.lpszClassName = "MDI_client_class";
2850     if (!RegisterClassA(&cls)) assert(0);
2851
2852     return TRUE;
2853 }
2854
2855 static void test_mdi_messages(void)
2856 {
2857     MDICREATESTRUCTA mdi_cs;
2858     CLIENTCREATESTRUCT client_cs;
2859     HWND mdi_frame, mdi_child, mdi_child2, active_child;
2860     BOOL zoomed;
2861     HMENU hMenu = CreateMenu();
2862
2863     assert(mdi_RegisterWindowClasses());
2864
2865     flush_sequence();
2866
2867     trace("creating MDI frame window\n");
2868     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2869                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2870                                 WS_MAXIMIZEBOX | WS_VISIBLE,
2871                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2872                                 GetDesktopWindow(), hMenu,
2873                                 GetModuleHandleA(0), NULL);
2874     assert(mdi_frame);
2875     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
2876
2877     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2878     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2879
2880     trace("creating MDI client window\n");
2881     client_cs.hWindowMenu = 0;
2882     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2883     mdi_client = CreateWindowExA(0, "MDI_client_class",
2884                                  NULL,
2885                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
2886                                  0, 0, 0, 0,
2887                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
2888     assert(mdi_client);
2889     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
2890
2891     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2892     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
2893
2894     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2895     ok(!active_child, "wrong active MDI child %p\n", active_child);
2896     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2897
2898     SetFocus(0);
2899     flush_sequence();
2900
2901     trace("creating invisible MDI child window\n");
2902     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2903                                 WS_CHILD,
2904                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2905                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2906     assert(mdi_child);
2907
2908     flush_sequence();
2909     ShowWindow(mdi_child, SW_SHOWNORMAL);
2910     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
2911
2912     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2913     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2914
2915     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2916     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2917
2918     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2919     ok(!active_child, "wrong active MDI child %p\n", active_child);
2920     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2921
2922     ShowWindow(mdi_child, SW_HIDE);
2923     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
2924     flush_sequence();
2925
2926     ShowWindow(mdi_child, SW_SHOW);
2927     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
2928
2929     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2930     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2931
2932     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2933     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2934
2935     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2936     ok(!active_child, "wrong active MDI child %p\n", active_child);
2937     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2938
2939     DestroyWindow(mdi_child);
2940     flush_sequence();
2941
2942     trace("creating visible MDI child window\n");
2943     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2944                                 WS_CHILD | WS_VISIBLE,
2945                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2946                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2947     assert(mdi_child);
2948     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
2949
2950     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2951     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2952
2953     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2954     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2955
2956     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2957     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2958     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2959     flush_sequence();
2960
2961     DestroyWindow(mdi_child);
2962     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2963
2964     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2965     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2966
2967     /* Win2k: MDI client still returns a just destroyed child as active
2968      * Win9x: MDI client returns 0
2969      */
2970     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2971     ok(active_child == mdi_child || /* win2k */
2972        !active_child, /* win9x */
2973        "wrong active MDI child %p\n", active_child);
2974     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2975
2976     flush_sequence();
2977
2978     trace("creating invisible MDI child window\n");
2979     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2980                                 WS_CHILD,
2981                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2982                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2983     assert(mdi_child2);
2984     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
2985
2986     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
2987     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
2988
2989     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2990     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2991
2992     /* Win2k: MDI client still returns a just destroyed child as active
2993      * Win9x: MDI client returns mdi_child2
2994      */
2995     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2996     ok(active_child == mdi_child || /* win2k */
2997        active_child == mdi_child2, /* win9x */
2998        "wrong active MDI child %p\n", active_child);
2999     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3000     flush_sequence();
3001
3002     ShowWindow(mdi_child2, SW_MAXIMIZE);
3003     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3004
3005     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3006     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3007
3008     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3009     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3010     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3011     flush_sequence();
3012
3013     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3014     ok(GetFocus() == mdi_child2 || /* win2k */
3015        GetFocus() == 0, /* win9x */
3016        "wrong focus window %p\n", GetFocus());
3017
3018     SetFocus(0);
3019     flush_sequence();
3020
3021     ShowWindow(mdi_child2, SW_HIDE);
3022     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3023
3024     ShowWindow(mdi_child2, SW_RESTORE);
3025     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3026     flush_sequence();
3027
3028     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3029     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3030
3031     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3032     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3033     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3034     flush_sequence();
3035
3036     SetFocus(0);
3037     flush_sequence();
3038
3039     ShowWindow(mdi_child2, SW_HIDE);
3040     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3041
3042     ShowWindow(mdi_child2, SW_SHOW);
3043     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3044
3045     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3046     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3047
3048     ShowWindow(mdi_child2, SW_MAXIMIZE);
3049     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3050
3051     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3052     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3053
3054     ShowWindow(mdi_child2, SW_RESTORE);
3055     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3056
3057     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3058     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3059
3060     ShowWindow(mdi_child2, SW_MINIMIZE);
3061     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3062
3063     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3064     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3065
3066     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3067     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3068     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3069     flush_sequence();
3070
3071     ShowWindow(mdi_child2, SW_RESTORE);
3072     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3073
3074     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3075     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3076
3077     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3078     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3079     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3080     flush_sequence();
3081
3082     SetFocus(0);
3083     flush_sequence();
3084
3085     ShowWindow(mdi_child2, SW_HIDE);
3086     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3087
3088     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3089     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3090
3091     DestroyWindow(mdi_child2);
3092     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3093
3094     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3095     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3096
3097     /* test for maximized MDI children */
3098     trace("creating maximized visible MDI child window 1\n");
3099     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3100                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3101                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3102                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3103     assert(mdi_child);
3104     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3105     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3106
3107     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3108     ok(GetFocus() == mdi_child || /* win2k */
3109        GetFocus() == 0, /* win9x */
3110        "wrong focus window %p\n", GetFocus());
3111
3112     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3113     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3114     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3115     flush_sequence();
3116
3117     trace("creating maximized visible MDI child window 2\n");
3118     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3119                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3120                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3121                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3122     assert(mdi_child2);
3123     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3124     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3125     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3126
3127     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3128     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3129
3130     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3131     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3132     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3133     flush_sequence();
3134
3135     trace("destroying maximized visible MDI child window 2\n");
3136     DestroyWindow(mdi_child2);
3137     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3138
3139     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3140
3141     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3142     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3143
3144     /* Win2k: MDI client still returns a just destroyed child as active
3145      * Win9x: MDI client returns 0
3146      */
3147     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3148     ok(active_child == mdi_child2 || /* win2k */
3149        !active_child, /* win9x */
3150        "wrong active MDI child %p\n", active_child);
3151     flush_sequence();
3152
3153     ShowWindow(mdi_child, SW_MAXIMIZE);
3154     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3155     flush_sequence();
3156
3157     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3158     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3159
3160     trace("re-creating maximized visible MDI child window 2\n");
3161     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3162                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3163                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3164                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3165     assert(mdi_child2);
3166     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3167     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3168     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3169
3170     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3171     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3172
3173     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3174     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3175     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3176     flush_sequence();
3177
3178     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3179     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3180     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3181
3182     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3183     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3184     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3185
3186     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3187     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3188     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3189     flush_sequence();
3190
3191     DestroyWindow(mdi_child);
3192     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3193
3194     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3195     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3196
3197     /* Win2k: MDI client still returns a just destroyed child as active
3198      * Win9x: MDI client returns 0
3199      */
3200     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3201     ok(active_child == mdi_child || /* win2k */
3202        !active_child, /* win9x */
3203        "wrong active MDI child %p\n", active_child);
3204     flush_sequence();
3205
3206     trace("creating maximized invisible MDI child window\n");
3207     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3208                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3209                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3210                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3211     assert(mdi_child2);
3212     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
3213     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3214     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3215     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3216
3217     /* Win2k: MDI client still returns a just destroyed child as active
3218      * Win9x: MDI client returns 0
3219      */
3220     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3221     ok(active_child == mdi_child || /* win2k */
3222        !active_child, /* win9x */
3223        "wrong active MDI child %p\n", active_child);
3224     flush_sequence();
3225
3226     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3227     ShowWindow(mdi_child2, SW_MAXIMIZE);
3228     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3229     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3230     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3231     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3232
3233     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3234     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3235     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3236     flush_sequence();
3237
3238     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3239     flush_sequence();
3240
3241     /* end of test for maximized MDI children */
3242     SetFocus(0);
3243     flush_sequence();
3244     trace("creating maximized visible MDI child window 1(Switch test)\n");
3245     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3246                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3247                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3248                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3249     assert(mdi_child);
3250     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3251     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3252
3253     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3254     ok(GetFocus() == mdi_child || /* win2k */
3255        GetFocus() == 0, /* win9x */
3256        "wrong focus window %p(Switch test)\n", GetFocus());
3257
3258     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3259     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3260     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3261     flush_sequence();
3262
3263     trace("creating maximized visible MDI child window 2(Switch test)\n");
3264     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3265                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3266                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3267                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3268     assert(mdi_child2);
3269     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3270
3271     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3272     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3273
3274     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3275     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3276
3277     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3278     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3279     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3280     flush_sequence();
3281
3282     trace("Switch child window.\n");
3283     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3284     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3285     trace("end of test for switch maximized MDI children\n");
3286
3287     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3288     flush_sequence();
3289
3290     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3291     flush_sequence();
3292
3293     SetFocus(0);
3294     flush_sequence();
3295     /* end of test for switch maximized MDI children */
3296
3297     mdi_cs.szClass = "MDI_child_Class";
3298     mdi_cs.szTitle = "MDI child";
3299     mdi_cs.hOwner = GetModuleHandleA(0);
3300     mdi_cs.x = 0;
3301     mdi_cs.y = 0;
3302     mdi_cs.cx = CW_USEDEFAULT;
3303     mdi_cs.cy = CW_USEDEFAULT;
3304     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3305     mdi_cs.lParam = 0;
3306     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3307     ok(mdi_child != 0, "MDI child creation failed\n");
3308     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3309
3310     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3311
3312     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3313     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3314
3315     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3316     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3317     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3318
3319     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3320     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3321     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3322     flush_sequence();
3323
3324     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3325     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3326
3327     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3328     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3329     ok(!active_child, "wrong active MDI child %p\n", active_child);
3330
3331     SetFocus(0);
3332     flush_sequence();
3333
3334     DestroyWindow(mdi_client);
3335     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3336
3337     /* test maximization of MDI child with invisible parent */
3338     client_cs.hWindowMenu = 0;
3339     mdi_client = CreateWindow("MDI_client_class",
3340                                  NULL,
3341                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3342                                  0, 0, 660, 430,
3343                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3344     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3345
3346     ShowWindow(mdi_client, SW_HIDE);
3347     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3348
3349     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3350                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3351                                 0, 0, 650, 440,
3352                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3353     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3354
3355     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3356     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3357     zoomed = IsZoomed(mdi_child);
3358     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3359     
3360     ShowWindow(mdi_client, SW_SHOW);
3361     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3362
3363     DestroyWindow(mdi_child);
3364     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3365
3366     /* end of test for maximization of MDI child with invisible parent */
3367
3368     DestroyWindow(mdi_client);
3369     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3370
3371     DestroyWindow(mdi_frame);
3372     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3373 }
3374 /************************* End of MDI test **********************************/
3375
3376 static void test_WM_SETREDRAW(HWND hwnd)
3377 {
3378     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3379
3380     flush_sequence();
3381
3382     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3383     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3384
3385     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3386     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3387
3388     flush_sequence();
3389     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3390     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3391
3392     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3393     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3394
3395     /* restore original WS_VISIBLE state */
3396     SetWindowLongA(hwnd, GWL_STYLE, style);
3397
3398     flush_sequence();
3399 }
3400
3401 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3402 {
3403     struct message msg;
3404
3405     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3406
3407     /* explicitly ignore WM_GETICON message */
3408     if (message == WM_GETICON) return 0;
3409
3410     switch (message)
3411     {
3412         /* ignore */
3413         case WM_MOUSEMOVE:
3414         case WM_SETCURSOR:
3415         case WM_DEVICECHANGE:
3416             return 0;
3417         case WM_NCHITTEST:
3418             return HTCLIENT;
3419
3420         case WM_WINDOWPOSCHANGING:
3421         case WM_WINDOWPOSCHANGED:
3422         {
3423             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3424
3425             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3426             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
3427                   winpos->hwnd, winpos->hwndInsertAfter,
3428                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3429             dump_winpos_flags(winpos->flags);
3430
3431             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3432              * in the high word for internal purposes
3433              */
3434             wParam = winpos->flags & 0xffff;
3435             /* We are not interested in the flags that don't match under XP and Win9x */
3436             wParam &= ~(SWP_NOZORDER);
3437             break;
3438         }
3439     }
3440
3441     msg.message = message;
3442     msg.flags = sent|wparam|lparam;
3443     msg.wParam = wParam;
3444     msg.lParam = lParam;
3445     add_message(&msg);
3446
3447     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3448     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3449     return 0;
3450 }
3451
3452 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3453 {
3454     DWORD style, exstyle;
3455     INT xmin, xmax;
3456     BOOL ret;
3457
3458     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3459     style = GetWindowLongA(hwnd, GWL_STYLE);
3460     /* do not be confused by WS_DLGFRAME set */
3461     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3462
3463     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3464     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3465
3466     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3467     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3468     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3469         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3470     else
3471         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3472
3473     style = GetWindowLongA(hwnd, GWL_STYLE);
3474     if (set) ok(style & set, "style %08x should be set\n", set);
3475     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3476
3477     /* a subsequent call should do nothing */
3478     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3479     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3480     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3481
3482     xmin = 0xdeadbeef;
3483     xmax = 0xdeadbeef;
3484     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3485     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3486     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3487     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3488     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3489     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3490 }
3491
3492 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3493 {
3494     DWORD style, exstyle;
3495     SCROLLINFO si;
3496     BOOL ret;
3497
3498     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3499     style = GetWindowLongA(hwnd, GWL_STYLE);
3500     /* do not be confused by WS_DLGFRAME set */
3501     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3502
3503     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3504     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3505
3506     si.cbSize = sizeof(si);
3507     si.fMask = SIF_RANGE;
3508     si.nMin = min;
3509     si.nMax = max;
3510     SetScrollInfo(hwnd, ctl, &si, TRUE);
3511     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3512         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3513     else
3514         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3515
3516     style = GetWindowLongA(hwnd, GWL_STYLE);
3517     if (set) ok(style & set, "style %08x should be set\n", set);
3518     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3519
3520     /* a subsequent call should do nothing */
3521     SetScrollInfo(hwnd, ctl, &si, TRUE);
3522     if (style & WS_HSCROLL)
3523         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3524     else if (style & WS_VSCROLL)
3525         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3526     else
3527         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3528
3529     si.fMask = SIF_PAGE;
3530     si.nPage = 5;
3531     SetScrollInfo(hwnd, ctl, &si, FALSE);
3532     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3533
3534     si.fMask = SIF_POS;
3535     si.nPos = max - 1;
3536     SetScrollInfo(hwnd, ctl, &si, FALSE);
3537     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3538
3539     si.fMask = SIF_RANGE;
3540     si.nMin = 0xdeadbeef;
3541     si.nMax = 0xdeadbeef;
3542     ret = GetScrollInfo(hwnd, ctl, &si);
3543     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3544     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3545     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3546     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3547 }
3548
3549 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3550 static void test_scroll_messages(HWND hwnd)
3551 {
3552     SCROLLINFO si;
3553     INT min, max;
3554     BOOL ret;
3555
3556     min = 0xdeadbeef;
3557     max = 0xdeadbeef;
3558     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3559     ok( ret, "GetScrollRange error %d\n", GetLastError());
3560     if (sequence->message != WmGetScrollRangeSeq[0].message)
3561         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3562     /* values of min and max are undefined */
3563     flush_sequence();
3564
3565     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3566     ok( ret, "SetScrollRange error %d\n", GetLastError());
3567     if (sequence->message != WmSetScrollRangeSeq[0].message)
3568         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3569     flush_sequence();
3570
3571     min = 0xdeadbeef;
3572     max = 0xdeadbeef;
3573     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3574     ok( ret, "GetScrollRange error %d\n", GetLastError());
3575     if (sequence->message != WmGetScrollRangeSeq[0].message)
3576         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3577     /* values of min and max are undefined */
3578     flush_sequence();
3579
3580     si.cbSize = sizeof(si);
3581     si.fMask = SIF_RANGE;
3582     si.nMin = 20;
3583     si.nMax = 160;
3584     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3585     if (sequence->message != WmSetScrollRangeSeq[0].message)
3586         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3587     flush_sequence();
3588
3589     si.fMask = SIF_PAGE;
3590     si.nPage = 10;
3591     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3592     if (sequence->message != WmSetScrollRangeSeq[0].message)
3593         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3594     flush_sequence();
3595
3596     si.fMask = SIF_POS;
3597     si.nPos = 20;
3598     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3599     if (sequence->message != WmSetScrollRangeSeq[0].message)
3600         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3601     flush_sequence();
3602
3603     si.fMask = SIF_RANGE;
3604     si.nMin = 0xdeadbeef;
3605     si.nMax = 0xdeadbeef;
3606     ret = GetScrollInfo(hwnd, SB_CTL, &si);
3607     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3608     if (sequence->message != WmGetScrollInfoSeq[0].message)
3609         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3610     /* values of min and max are undefined */
3611     flush_sequence();
3612
3613     /* set WS_HSCROLL */
3614     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3615     /* clear WS_HSCROLL */
3616     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3617
3618     /* set WS_HSCROLL */
3619     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3620     /* clear WS_HSCROLL */
3621     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3622
3623     /* set WS_VSCROLL */
3624     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3625     /* clear WS_VSCROLL */
3626     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3627
3628     /* set WS_VSCROLL */
3629     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3630     /* clear WS_VSCROLL */
3631     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3632 }
3633
3634 static void test_showwindow(void)
3635 {
3636     HWND hwnd, hchild;
3637     RECT rc;
3638
3639     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3640                            100, 100, 200, 200, 0, 0, 0, NULL);
3641     ok (hwnd != 0, "Failed to create overlapped window\n");
3642     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3643                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3644     ok (hchild != 0, "Failed to create child\n");
3645     flush_sequence();
3646
3647     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3648     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3649     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3650     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3651     trace("done\n");
3652
3653     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3654     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3655     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3656     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3657     trace("done\n");
3658     /* back to invisible */
3659     ShowWindow(hchild, SW_HIDE);
3660     ShowWindow(hwnd, SW_HIDE);
3661     flush_sequence();
3662     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3663     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3664     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3665     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3666     trace("done\n");
3667     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3668     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3669     flush_sequence();
3670     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3671     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3672     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3673     trace("done\n");
3674     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3675     ShowWindow( hwnd, SW_SHOW);
3676     flush_sequence();
3677     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3678     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3679     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3680     trace("done\n");
3681
3682     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3683     ShowWindow( hchild, SW_HIDE);
3684     flush_sequence();
3685     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3686     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3687     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3688     trace("done\n");
3689
3690     SetCapture(hchild);
3691     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3692     DestroyWindow(hchild);
3693     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3694
3695     DestroyWindow(hwnd);
3696     flush_sequence();
3697
3698     /* Popup windows */
3699     /* Test 1:
3700      * 1. Create invisible maximized popup window.
3701      * 2. Move and resize it.
3702      * 3. Show it maximized.
3703      */
3704     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3705     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3706                            100, 100, 200, 200, 0, 0, 0, NULL);
3707     ok (hwnd != 0, "Failed to create popup window\n");
3708     ok(IsZoomed(hwnd), "window should be maximized\n");
3709     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3710     trace("done\n");
3711
3712     GetWindowRect(hwnd, &rc);
3713     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3714         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3715         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3716         rc.left, rc.top, rc.right, rc.bottom);
3717     /* Reset window's size & position */
3718     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3719     ok(IsZoomed(hwnd), "window should be maximized\n");
3720     flush_sequence();
3721
3722     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3723     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3724     ok(IsZoomed(hwnd), "window should be maximized\n");
3725     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3726     trace("done\n");
3727
3728     GetWindowRect(hwnd, &rc);
3729     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3730         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3731         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3732         rc.left, rc.top, rc.right, rc.bottom);
3733     DestroyWindow(hwnd);
3734     flush_sequence();
3735
3736     /* Test 2:
3737      * 1. Create invisible maximized popup window.
3738      * 2. Show it maximized.
3739      */
3740     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3741     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3742                            100, 100, 200, 200, 0, 0, 0, NULL);
3743     ok (hwnd != 0, "Failed to create popup window\n");
3744     ok(IsZoomed(hwnd), "window should be maximized\n");
3745     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3746     trace("done\n");
3747
3748     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3749     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3750     ok(IsZoomed(hwnd), "window should be maximized\n");
3751     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
3752     trace("done\n");
3753     DestroyWindow(hwnd);
3754     flush_sequence();
3755
3756     /* Test 3:
3757      * 1. Create visible maximized popup window.
3758      */
3759     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3760     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3761                            100, 100, 200, 200, 0, 0, 0, NULL);
3762     ok (hwnd != 0, "Failed to create popup window\n");
3763     ok(IsZoomed(hwnd), "window should be maximized\n");
3764     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3765     trace("done\n");
3766     DestroyWindow(hwnd);
3767     flush_sequence();
3768
3769     /* Test 4:
3770      * 1. Create visible popup window.
3771      * 2. Maximize it.
3772      */
3773     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3774     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3775                            100, 100, 200, 200, 0, 0, 0, NULL);
3776     ok (hwnd != 0, "Failed to create popup window\n");
3777     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
3778     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
3779     trace("done\n");
3780
3781     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3782     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3783     ok(IsZoomed(hwnd), "window should be maximized\n");
3784     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3785     trace("done\n");
3786     DestroyWindow(hwnd);
3787     flush_sequence();
3788 }
3789
3790 static void test_sys_menu(void)
3791 {
3792     HWND hwnd;
3793     HMENU hmenu;
3794     UINT state;
3795
3796     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3797                            100, 100, 200, 200, 0, 0, 0, NULL);
3798     ok (hwnd != 0, "Failed to create overlapped window\n");
3799
3800     flush_sequence();
3801
3802     /* test existing window without CS_NOCLOSE style */
3803     hmenu = GetSystemMenu(hwnd, FALSE);
3804     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3805
3806     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3807     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3808     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3809
3810     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3811     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3812
3813     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3814     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3815     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3816
3817     EnableMenuItem(hmenu, SC_CLOSE, 0);
3818     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3819
3820     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3821     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3822     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3823
3824     /* test whether removing WS_SYSMENU destroys a system menu */
3825     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
3826     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3827     flush_sequence();
3828     hmenu = GetSystemMenu(hwnd, FALSE);
3829     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3830
3831     DestroyWindow(hwnd);
3832
3833     /* test new window with CS_NOCLOSE style */
3834     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3835                            100, 100, 200, 200, 0, 0, 0, NULL);
3836     ok (hwnd != 0, "Failed to create overlapped window\n");
3837
3838     hmenu = GetSystemMenu(hwnd, FALSE);
3839     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
3840
3841     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3842     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3843
3844     DestroyWindow(hwnd);
3845
3846     /* test new window without WS_SYSMENU style */
3847     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
3848                            100, 100, 200, 200, 0, 0, 0, NULL);
3849     ok(hwnd != 0, "Failed to create overlapped window\n");
3850
3851     hmenu = GetSystemMenu(hwnd, FALSE);
3852     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
3853
3854     DestroyWindow(hwnd);
3855 }
3856
3857 /* For shown WS_OVERLAPPEDWINDOW */
3858 static const struct message WmSetIcon_1[] = {
3859     { WM_SETICON, sent },
3860     { 0x00AE, sent|defwinproc|optional }, /* XP */
3861     { WM_GETTEXT, sent|defwinproc|optional },
3862     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
3863     { 0 }
3864 };
3865
3866 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
3867 static const struct message WmSetIcon_2[] = {
3868     { WM_SETICON, sent },
3869     { 0 }
3870 };
3871
3872 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
3873 static const struct message WmInitEndSession[] = {
3874     { 0x003B, sent },
3875     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
3876     { 0 }
3877 };
3878
3879 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
3880 static const struct message WmInitEndSession_2[] = {
3881     { 0x003B, sent },
3882     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
3883     { 0 }
3884 };
3885
3886 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
3887 static const struct message WmInitEndSession_3[] = {
3888     { 0x003B, sent },
3889     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
3890     { 0 }
3891 };
3892
3893 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
3894 static const struct message WmInitEndSession_4[] = {
3895     { 0x003B, sent },
3896     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
3897     { 0 }
3898 };
3899
3900 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
3901 static const struct message WmInitEndSession_5[] = {
3902     { 0x003B, sent },
3903     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 1, ENDSESSION_LOGOFF },
3904     { 0 }
3905 };
3906
3907 static void test_MsgWaitForMultipleObjects(HWND hwnd)
3908 {
3909     DWORD ret;
3910     MSG msg;
3911
3912     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3913     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3914
3915     PostMessageA(hwnd, WM_USER, 0, 0);
3916
3917     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3918     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3919
3920     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3921     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3922
3923     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3924     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3925
3926     PostMessageA(hwnd, WM_USER, 0, 0);
3927
3928     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3929     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3930
3931     ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
3932     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3933
3934     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
3935     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3936     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
3937
3938     PostMessageA(hwnd, WM_USER, 0, 0);
3939
3940     /* new incoming message causes it to become signaled again */
3941     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3942     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
3943
3944     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3945     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3946     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3947     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3948 }
3949
3950 /* test if we receive the right sequence of messages */
3951 static void test_messages(void)
3952 {
3953     HWND hwnd, hparent, hchild;
3954     HWND hchild2, hbutton;
3955     HMENU hmenu;
3956     MSG msg;
3957     LRESULT res;
3958
3959     flush_sequence();
3960
3961     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3962                            100, 100, 200, 200, 0, 0, 0, NULL);
3963     ok (hwnd != 0, "Failed to create overlapped window\n");
3964     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3965
3966     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
3967     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
3968     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
3969
3970     /* test WM_SETREDRAW on a not visible top level window */
3971     test_WM_SETREDRAW(hwnd);
3972
3973     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3974     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
3975     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
3976
3977     ok(GetActiveWindow() == hwnd, "window should be active\n");
3978     ok(GetFocus() == hwnd, "window should have input focus\n");
3979     ShowWindow(hwnd, SW_HIDE);
3980     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
3981
3982     ShowWindow(hwnd, SW_SHOW);
3983     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
3984
3985     ShowWindow(hwnd, SW_HIDE);
3986     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
3987
3988     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3989     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
3990
3991     ShowWindow(hwnd, SW_RESTORE);
3992     /* FIXME: add ok_sequence() here */
3993     flush_sequence();
3994
3995     ShowWindow(hwnd, SW_MINIMIZE);
3996     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
3997     flush_sequence();
3998
3999     ShowWindow(hwnd, SW_RESTORE);
4000     /* FIXME: add ok_sequence() here */
4001     flush_sequence();
4002
4003     ShowWindow(hwnd, SW_SHOW);
4004     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4005
4006     ok(GetActiveWindow() == hwnd, "window should be active\n");
4007     ok(GetFocus() == hwnd, "window should have input focus\n");
4008     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4009     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4010     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4011     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4012
4013     /* test WM_SETREDRAW on a visible top level window */
4014     ShowWindow(hwnd, SW_SHOW);
4015     test_WM_SETREDRAW(hwnd);
4016
4017     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4018     test_scroll_messages(hwnd);
4019
4020     /* test resizing and moving */
4021     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4022     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4023     flush_events();
4024     flush_sequence();
4025     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4026     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4027     flush_events();
4028     flush_sequence();
4029     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
4030     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4031     flush_events();
4032     flush_sequence();
4033
4034     /* popups don't get WM_GETMINMAXINFO */
4035     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4036     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4037     flush_sequence();
4038     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4039     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4040
4041     DestroyWindow(hwnd);
4042     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4043
4044     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4045                               100, 100, 200, 200, 0, 0, 0, NULL);
4046     ok (hparent != 0, "Failed to create parent window\n");
4047     flush_sequence();
4048
4049     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4050                              0, 0, 10, 10, hparent, 0, 0, NULL);
4051     ok (hchild != 0, "Failed to create child window\n");
4052     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4053     DestroyWindow(hchild);
4054     flush_sequence();
4055
4056     /* visible child window with a caption */
4057     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4058                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4059                              0, 0, 10, 10, hparent, 0, 0, NULL);
4060     ok (hchild != 0, "Failed to create child window\n");
4061     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4062
4063     trace("testing scroll APIs on a visible child window %p\n", hchild);
4064     test_scroll_messages(hchild);
4065
4066     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4067     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4068
4069     DestroyWindow(hchild);
4070     flush_sequence();
4071
4072     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4073                              0, 0, 10, 10, hparent, 0, 0, NULL);
4074     ok (hchild != 0, "Failed to create child window\n");
4075     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4076     
4077     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4078                                100, 100, 50, 50, hparent, 0, 0, NULL);
4079     ok (hchild2 != 0, "Failed to create child2 window\n");
4080     flush_sequence();
4081
4082     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4083                               0, 100, 50, 50, hchild, 0, 0, NULL);
4084     ok (hbutton != 0, "Failed to create button window\n");
4085
4086     /* test WM_SETREDRAW on a not visible child window */
4087     test_WM_SETREDRAW(hchild);
4088
4089     ShowWindow(hchild, SW_SHOW);
4090     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4091
4092     /* check parent messages too */
4093     log_all_parent_messages++;
4094     ShowWindow(hchild, SW_HIDE);
4095     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4096     log_all_parent_messages--;
4097
4098     ShowWindow(hchild, SW_SHOW);
4099     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4100
4101     ShowWindow(hchild, SW_HIDE);
4102     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4103
4104     ShowWindow(hchild, SW_SHOW);
4105     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4106
4107     /* test WM_SETREDRAW on a visible child window */
4108     test_WM_SETREDRAW(hchild);
4109
4110     log_all_parent_messages++;
4111     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4112     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4113     log_all_parent_messages--;
4114
4115     ShowWindow(hchild, SW_HIDE);
4116     flush_sequence();
4117     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4118     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4119
4120     ShowWindow(hchild, SW_HIDE);
4121     flush_sequence();
4122     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4123     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4124
4125     /* DestroyWindow sequence below expects that a child has focus */
4126     SetFocus(hchild);
4127     flush_sequence();
4128
4129     DestroyWindow(hchild);
4130     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4131     DestroyWindow(hchild2);
4132     DestroyWindow(hbutton);
4133
4134     flush_sequence();
4135     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4136                              0, 0, 100, 100, hparent, 0, 0, NULL);
4137     ok (hchild != 0, "Failed to create child popup window\n");
4138     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4139     DestroyWindow(hchild);
4140
4141     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4142     flush_sequence();
4143     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4144                              0, 0, 100, 100, hparent, 0, 0, NULL);
4145     ok (hchild != 0, "Failed to create popup window\n");
4146     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4147     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4148     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4149     flush_sequence();
4150     ShowWindow(hchild, SW_SHOW);
4151     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4152     flush_sequence();
4153     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4154     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4155     flush_sequence();
4156     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4157     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", TRUE);
4158     DestroyWindow(hchild);
4159
4160     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4161      * changes nothing in message sequences.
4162      */
4163     flush_sequence();
4164     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4165                              0, 0, 100, 100, hparent, 0, 0, NULL);
4166     ok (hchild != 0, "Failed to create popup window\n");
4167     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4168     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4169     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4170     flush_sequence();
4171     ShowWindow(hchild, SW_SHOW);
4172     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4173     flush_sequence();
4174     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4175     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4176     DestroyWindow(hchild);
4177
4178     flush_sequence();
4179     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4180                            0, 0, 100, 100, hparent, 0, 0, NULL);
4181     ok(hwnd != 0, "Failed to create custom dialog window\n");
4182     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4183
4184     /*
4185     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4186     test_scroll_messages(hwnd);
4187     */
4188
4189     flush_sequence();
4190
4191     test_def_id = 1;
4192     SendMessage(hwnd, WM_NULL, 0, 0);
4193
4194     flush_sequence();
4195     after_end_dialog = 1;
4196     EndDialog( hwnd, 0 );
4197     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4198
4199     DestroyWindow(hwnd);
4200     after_end_dialog = 0;
4201     test_def_id = 0;
4202
4203     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4204                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4205     ok(hwnd != 0, "Failed to create custom dialog window\n");
4206     flush_sequence();
4207     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4208     ShowWindow(hwnd, SW_SHOW);
4209     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4210     DestroyWindow(hwnd);
4211
4212     flush_sequence();
4213     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4214     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4215
4216     DestroyWindow(hparent);
4217     flush_sequence();
4218
4219     /* Message sequence for SetMenu */
4220     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4221     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4222
4223     hmenu = CreateMenu();
4224     ok (hmenu != 0, "Failed to create menu\n");
4225     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4226     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4227                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4228     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4229     ok (SetMenu(hwnd, 0), "SetMenu\n");
4230     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4231     ok (SetMenu(hwnd, 0), "SetMenu\n");
4232     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4233     ShowWindow(hwnd, SW_SHOW);
4234     UpdateWindow( hwnd );
4235     flush_events();
4236     flush_sequence();
4237     ok (SetMenu(hwnd, 0), "SetMenu\n");
4238     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4239     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4240     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4241
4242     UpdateWindow( hwnd );
4243     flush_events();
4244     flush_sequence();
4245     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4246     flush_events();
4247     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4248
4249     DestroyWindow(hwnd);
4250     flush_sequence();
4251
4252     /* Message sequence for EnableWindow */
4253     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4254                               100, 100, 200, 200, 0, 0, 0, NULL);
4255     ok (hparent != 0, "Failed to create parent window\n");
4256     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4257                              0, 0, 10, 10, hparent, 0, 0, NULL);
4258     ok (hchild != 0, "Failed to create child window\n");
4259
4260     SetFocus(hchild);
4261     flush_events();
4262     flush_sequence();
4263
4264     EnableWindow(hparent, FALSE);
4265     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4266
4267     EnableWindow(hparent, TRUE);
4268     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4269
4270     flush_events();
4271     flush_sequence();
4272
4273     test_MsgWaitForMultipleObjects(hparent);
4274
4275     /* the following test causes an exception in user.exe under win9x */
4276     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4277     {
4278         DestroyWindow(hparent);
4279         flush_sequence();
4280         return;
4281     }
4282     PostMessageW( hparent, WM_USER+1, 0, 0 );
4283     /* PeekMessage(NULL) fails, but still removes the message */
4284     SetLastError(0xdeadbeef);
4285     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4286     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4287         GetLastError() == 0xdeadbeef, /* NT4 */
4288         "last error is %d\n", GetLastError() );
4289     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4290     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4291
4292     DestroyWindow(hchild);
4293     DestroyWindow(hparent);
4294     flush_sequence();
4295
4296     /* Message sequences for WM_SETICON */
4297     trace("testing WM_SETICON\n");
4298     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4299                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4300                            NULL, NULL, 0);
4301     ShowWindow(hwnd, SW_SHOW);
4302     UpdateWindow(hwnd);
4303     flush_events();
4304     flush_sequence();
4305     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4306     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4307
4308     ShowWindow(hwnd, SW_HIDE);
4309     flush_events();
4310     flush_sequence();
4311     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4312     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4313     DestroyWindow(hwnd);
4314     flush_sequence();
4315
4316     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4317                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4318                            NULL, NULL, 0);
4319     ShowWindow(hwnd, SW_SHOW);
4320     UpdateWindow(hwnd);
4321     flush_events();
4322     flush_sequence();
4323     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4324     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4325
4326     ShowWindow(hwnd, SW_HIDE);
4327     flush_events();
4328     flush_sequence();
4329     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4330     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4331
4332     flush_sequence();
4333     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4334     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4335     todo_wine
4336     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4337     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4338     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4339     todo_wine
4340     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4341     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4342     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4343     todo_wine
4344     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4345
4346     flush_sequence();
4347     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4348     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4349     todo_wine
4350     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4351     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4352     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4353     todo_wine
4354     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4355
4356     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4357     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4358     todo_wine
4359     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4360
4361     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4362     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4363     todo_wine
4364     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4365
4366     DestroyWindow(hwnd);
4367     flush_sequence();
4368 }
4369
4370 static void invisible_parent_tests(void)
4371 {
4372     HWND hparent, hchild;
4373
4374     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4375                               100, 100, 200, 200, 0, 0, 0, NULL);
4376     ok (hparent != 0, "Failed to create parent window\n");
4377     flush_sequence();
4378
4379     /* test showing child with hidden parent */
4380
4381     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4382                              0, 0, 10, 10, hparent, 0, 0, NULL);
4383     ok (hchild != 0, "Failed to create child window\n");
4384     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4385
4386     ShowWindow( hchild, SW_MINIMIZE );
4387     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4388     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4389     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4390
4391     /* repeat */
4392     flush_events();
4393     flush_sequence();
4394     ShowWindow( hchild, SW_MINIMIZE );
4395     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4396
4397     DestroyWindow(hchild);
4398     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4399                              0, 0, 10, 10, hparent, 0, 0, NULL);
4400     flush_sequence();
4401
4402     ShowWindow( hchild, SW_MAXIMIZE );
4403     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4404     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4405     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4406
4407     /* repeat */
4408     flush_events();
4409     flush_sequence();
4410     ShowWindow( hchild, SW_MAXIMIZE );
4411     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4412
4413     DestroyWindow(hchild);
4414     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4415                              0, 0, 10, 10, hparent, 0, 0, NULL);
4416     flush_sequence();
4417
4418     ShowWindow( hchild, SW_RESTORE );
4419     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4420     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4421     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4422
4423     DestroyWindow(hchild);
4424     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4425                              0, 0, 10, 10, hparent, 0, 0, NULL);
4426     flush_sequence();
4427
4428     ShowWindow( hchild, SW_SHOWMINIMIZED );
4429     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4430     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4431     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4432
4433     /* repeat */
4434     flush_events();
4435     flush_sequence();
4436     ShowWindow( hchild, SW_SHOWMINIMIZED );
4437     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4438
4439     DestroyWindow(hchild);
4440     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4441                              0, 0, 10, 10, hparent, 0, 0, NULL);
4442     flush_sequence();
4443
4444     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4445     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4446     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4447     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4448     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4449
4450     DestroyWindow(hchild);
4451     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4452                              0, 0, 10, 10, hparent, 0, 0, NULL);
4453     flush_sequence();
4454
4455     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4456     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4457     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4458     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4459
4460     /* repeat */
4461     flush_events();
4462     flush_sequence();
4463     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4464     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4465
4466     DestroyWindow(hchild);
4467     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4468                              0, 0, 10, 10, hparent, 0, 0, NULL);
4469     flush_sequence();
4470
4471     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4472     ShowWindow( hchild, SW_FORCEMINIMIZE );
4473     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4474 todo_wine {
4475     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4476 }
4477     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4478
4479     DestroyWindow(hchild);
4480     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4481                              0, 0, 10, 10, hparent, 0, 0, NULL);
4482     flush_sequence();
4483
4484     ShowWindow( hchild, SW_SHOWNA );
4485     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4486     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4487     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4488
4489     /* repeat */
4490     flush_events();
4491     flush_sequence();
4492     ShowWindow( hchild, SW_SHOWNA );
4493     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4494
4495     DestroyWindow(hchild);
4496     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4497                              0, 0, 10, 10, hparent, 0, 0, NULL);
4498     flush_sequence();
4499
4500     ShowWindow( hchild, SW_SHOW );
4501     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4502     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4503     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4504
4505     /* repeat */
4506     flush_events();
4507     flush_sequence();
4508     ShowWindow( hchild, SW_SHOW );
4509     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4510
4511     ShowWindow( hchild, SW_HIDE );
4512     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4513     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4514     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4515
4516     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4517     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4518     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4519     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4520
4521     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4522     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4523     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4524     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4525
4526     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4527     flush_sequence();
4528     DestroyWindow(hchild);
4529     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4530
4531     DestroyWindow(hparent);
4532     flush_sequence();
4533 }
4534
4535 /****************** button message test *************************/
4536 static const struct message WmSetFocusButtonSeq[] =
4537 {
4538     { HCBT_SETFOCUS, hook },
4539     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4540     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4541     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4542     { WM_SETFOCUS, sent|wparam, 0 },
4543     { WM_CTLCOLORBTN, sent|defwinproc },
4544     { 0 }
4545 };
4546 static const struct message WmKillFocusButtonSeq[] =
4547 {
4548     { HCBT_SETFOCUS, hook },
4549     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4550     { WM_KILLFOCUS, sent|wparam, 0 },
4551     { WM_CTLCOLORBTN, sent|defwinproc },
4552     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4553     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4554     { 0 }
4555 };
4556 static const struct message WmSetFocusStaticSeq[] =
4557 {
4558     { HCBT_SETFOCUS, hook },
4559     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4560     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4561     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4562     { WM_SETFOCUS, sent|wparam, 0 },
4563     { WM_CTLCOLORSTATIC, sent|defwinproc },
4564     { 0 }
4565 };
4566 static const struct message WmKillFocusStaticSeq[] =
4567 {
4568     { HCBT_SETFOCUS, hook },
4569     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4570     { WM_KILLFOCUS, sent|wparam, 0 },
4571     { WM_CTLCOLORSTATIC, sent|defwinproc },
4572     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4573     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4574     { 0 }
4575 };
4576 static const struct message WmLButtonDownSeq[] =
4577 {
4578     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4579     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4580     { HCBT_SETFOCUS, hook },
4581     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4582     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4583     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4584     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4585     { WM_CTLCOLORBTN, sent|defwinproc },
4586     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4587     { WM_CTLCOLORBTN, sent|defwinproc },
4588     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4589     { 0 }
4590 };
4591 static const struct message WmLButtonUpSeq[] =
4592 {
4593     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4594     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4595     { WM_CTLCOLORBTN, sent|defwinproc },
4596     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4597     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4598     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4599     { 0 }
4600 };
4601 static const struct message WmSetFontButtonSeq[] =
4602 {
4603     { WM_SETFONT, sent },
4604     { WM_PAINT, sent },
4605     { WM_ERASEBKGND, sent|defwinproc|optional },
4606     { WM_CTLCOLORBTN, sent|defwinproc },
4607     { 0 }
4608 };
4609
4610 static WNDPROC old_button_proc;
4611
4612 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4613 {
4614     static long defwndproc_counter = 0;
4615     LRESULT ret;
4616     struct message msg;
4617
4618     trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4619
4620     /* explicitly ignore WM_GETICON message */
4621     if (message == WM_GETICON) return 0;
4622
4623     msg.message = message;
4624     msg.flags = sent|wparam|lparam;
4625     if (defwndproc_counter) msg.flags |= defwinproc;
4626     msg.wParam = wParam;
4627     msg.lParam = lParam;
4628     add_message(&msg);
4629
4630     if (message == BM_SETSTATE)
4631         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4632
4633     defwndproc_counter++;
4634     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4635     defwndproc_counter--;
4636
4637     return ret;
4638 }
4639
4640 static void subclass_button(void)
4641 {
4642     WNDCLASSA cls;
4643
4644     if (!GetClassInfoA(0, "button", &cls)) assert(0);
4645
4646     old_button_proc = cls.lpfnWndProc;
4647
4648     cls.hInstance = GetModuleHandle(0);
4649     cls.lpfnWndProc = button_hook_proc;
4650     cls.lpszClassName = "my_button_class";
4651     UnregisterClass(cls.lpszClassName, cls.hInstance);
4652     if (!RegisterClassA(&cls)) assert(0);
4653 }
4654
4655 static void test_button_messages(void)
4656 {
4657     static const struct
4658     {
4659         DWORD style;
4660         DWORD dlg_code;
4661         const struct message *setfocus;
4662         const struct message *killfocus;
4663     } button[] = {
4664         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4665           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4666         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4667           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4668         { BS_CHECKBOX, DLGC_BUTTON,
4669           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4670         { BS_AUTOCHECKBOX, DLGC_BUTTON,
4671           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4672         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4673           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4674         { BS_3STATE, DLGC_BUTTON,
4675           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4676         { BS_AUTO3STATE, DLGC_BUTTON,
4677           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4678         { BS_GROUPBOX, DLGC_STATIC,
4679           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4680         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4681           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4682         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
4683           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4684         { BS_OWNERDRAW, DLGC_BUTTON,
4685           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
4686     };
4687     unsigned int i;
4688     HWND hwnd;
4689     DWORD dlg_code;
4690     HFONT zfont;
4691
4692     subclass_button();
4693
4694     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
4695     {
4696         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
4697                                0, 0, 50, 14, 0, 0, 0, NULL);
4698         ok(hwnd != 0, "Failed to create button window\n");
4699
4700         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4701         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4702
4703         ShowWindow(hwnd, SW_SHOW);
4704         UpdateWindow(hwnd);
4705         SetFocus(0);
4706         flush_sequence();
4707
4708         trace("button style %08x\n", button[i].style);
4709         SetFocus(hwnd);
4710         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
4711
4712         SetFocus(0);
4713         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
4714
4715         DestroyWindow(hwnd);
4716     }
4717
4718     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
4719                            0, 0, 50, 14, 0, 0, 0, NULL);
4720     ok(hwnd != 0, "Failed to create button window\n");
4721
4722     SetFocus(0);
4723     flush_events();
4724     flush_sequence();
4725
4726     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
4727     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
4728
4729     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
4730     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
4731
4732     flush_sequence();
4733     zfont = (HFONT)GetStockObject(SYSTEM_FONT);
4734     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
4735     UpdateWindow(hwnd);
4736     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
4737
4738     DestroyWindow(hwnd);
4739 }
4740
4741 /****************** static message test *************************/
4742 static const struct message WmSetFontStaticSeq[] =
4743 {
4744     { WM_SETFONT, sent },
4745     { WM_PAINT, sent|defwinproc },
4746     { WM_ERASEBKGND, sent|defwinproc|optional },
4747     { WM_CTLCOLORSTATIC, sent|defwinproc },
4748     { 0 }
4749 };
4750
4751 static WNDPROC old_static_proc;
4752
4753 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4754 {
4755     static long defwndproc_counter = 0;
4756     LRESULT ret;
4757     struct message msg;
4758
4759     trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4760
4761     /* explicitly ignore WM_GETICON message */
4762     if (message == WM_GETICON) return 0;
4763
4764     msg.message = message;
4765     msg.flags = sent|wparam|lparam;
4766     if (defwndproc_counter) msg.flags |= defwinproc;
4767     msg.wParam = wParam;
4768     msg.lParam = lParam;
4769     add_message(&msg);
4770
4771
4772     defwndproc_counter++;
4773     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
4774     defwndproc_counter--;
4775
4776     return ret;
4777 }
4778
4779 static void subclass_static(void)
4780 {
4781     WNDCLASSA cls;
4782
4783     if (!GetClassInfoA(0, "static", &cls)) assert(0);
4784
4785     old_static_proc = cls.lpfnWndProc;
4786
4787     cls.hInstance = GetModuleHandle(0);
4788     cls.lpfnWndProc = static_hook_proc;
4789     cls.lpszClassName = "my_static_class";
4790     UnregisterClass(cls.lpszClassName, cls.hInstance);
4791     if (!RegisterClassA(&cls)) assert(0);
4792 }
4793
4794 static void test_static_messages(void)
4795 {
4796     /* FIXME: make as comprehensive as the button message test */
4797     static const struct
4798     {
4799         DWORD style;
4800         DWORD dlg_code;
4801         const struct message *setfont;
4802     } static_ctrl[] = {
4803         { SS_LEFT, DLGC_STATIC,
4804           WmSetFontStaticSeq }
4805     };
4806     unsigned int i;
4807     HWND hwnd;
4808     DWORD dlg_code;
4809
4810     subclass_static();
4811
4812     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
4813     {
4814         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
4815                                0, 0, 50, 14, 0, 0, 0, NULL);
4816         ok(hwnd != 0, "Failed to create static window\n");
4817
4818         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
4819         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
4820
4821         ShowWindow(hwnd, SW_SHOW);
4822         UpdateWindow(hwnd);
4823         SetFocus(0);
4824         flush_sequence();
4825
4826         trace("static style %08x\n", static_ctrl[i].style);
4827         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
4828         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
4829
4830         DestroyWindow(hwnd);
4831     }
4832 }
4833
4834 /************* painting message test ********************/
4835
4836 void dump_region(HRGN hrgn)
4837 {
4838     DWORD i, size;
4839     RGNDATA *data = NULL;
4840     RECT *rect;
4841
4842     if (!hrgn)
4843     {
4844         printf( "null region\n" );
4845         return;
4846     }
4847     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
4848     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
4849     GetRegionData( hrgn, size, data );
4850     printf("%d rects:", data->rdh.nCount );
4851     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
4852         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
4853     printf("\n");
4854     HeapFree( GetProcessHeap(), 0, data );
4855 }
4856
4857 static void check_update_rgn( HWND hwnd, HRGN hrgn )
4858 {
4859     INT ret;
4860     RECT r1, r2;
4861     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
4862     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
4863
4864     ret = GetUpdateRgn( hwnd, update, FALSE );
4865     ok( ret != ERROR, "GetUpdateRgn failed\n" );
4866     if (ret == NULLREGION)
4867     {
4868         ok( !hrgn, "Update region shouldn't be empty\n" );
4869     }
4870     else
4871     {
4872         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
4873         {
4874             ok( 0, "Regions are different\n" );
4875             if (winetest_debug > 0)
4876             {
4877                 printf( "Update region: " );
4878                 dump_region( update );
4879                 printf( "Wanted region: " );
4880                 dump_region( hrgn );
4881             }
4882         }
4883     }
4884     GetRgnBox( update, &r1 );
4885     GetUpdateRect( hwnd, &r2, FALSE );
4886     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
4887         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
4888         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
4889
4890     DeleteObject( tmp );
4891     DeleteObject( update );
4892 }
4893
4894 static const struct message WmInvalidateRgn[] = {
4895     { WM_NCPAINT, sent },
4896     { WM_GETTEXT, sent|defwinproc|optional },
4897     { 0 }
4898 };
4899
4900 static const struct message WmGetUpdateRect[] = {
4901     { WM_NCPAINT, sent },
4902     { WM_GETTEXT, sent|defwinproc|optional },
4903     { WM_PAINT, sent },
4904     { 0 }
4905 };
4906
4907 static const struct message WmInvalidateFull[] = {
4908     { WM_NCPAINT, sent|wparam, 1 },
4909     { WM_GETTEXT, sent|defwinproc|optional },
4910     { 0 }
4911 };
4912
4913 static const struct message WmInvalidateErase[] = {
4914     { WM_NCPAINT, sent|wparam, 1 },
4915     { WM_GETTEXT, sent|defwinproc|optional },
4916     { WM_ERASEBKGND, sent },
4917     { 0 }
4918 };
4919
4920 static const struct message WmInvalidatePaint[] = {
4921     { WM_PAINT, sent },
4922     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
4923     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4924     { 0 }
4925 };
4926
4927 static const struct message WmInvalidateErasePaint[] = {
4928     { WM_PAINT, sent },
4929     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
4930     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4931     { WM_ERASEBKGND, sent|beginpaint },
4932     { 0 }
4933 };
4934
4935 static const struct message WmInvalidateErasePaint2[] = {
4936     { WM_PAINT, sent },
4937     { WM_NCPAINT, sent|beginpaint },
4938     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4939     { WM_ERASEBKGND, sent|beginpaint },
4940     { 0 }
4941 };
4942
4943 static const struct message WmErase[] = {
4944     { WM_ERASEBKGND, sent },
4945     { 0 }
4946 };
4947
4948 static const struct message WmPaint[] = {
4949     { WM_PAINT, sent },
4950     { 0 }
4951 };
4952
4953 static const struct message WmParentOnlyPaint[] = {
4954     { WM_PAINT, sent|parent },
4955     { 0 }
4956 };
4957
4958 static const struct message WmInvalidateParent[] = {
4959     { WM_NCPAINT, sent|parent },
4960     { WM_GETTEXT, sent|defwinproc|parent|optional },
4961     { WM_ERASEBKGND, sent|parent },
4962     { 0 }
4963 };
4964
4965 static const struct message WmInvalidateParentChild[] = {
4966     { WM_NCPAINT, sent|parent },
4967     { WM_GETTEXT, sent|defwinproc|parent|optional },
4968     { WM_ERASEBKGND, sent|parent },
4969     { WM_NCPAINT, sent },
4970     { WM_GETTEXT, sent|defwinproc|optional },
4971     { WM_ERASEBKGND, sent },
4972     { 0 }
4973 };
4974
4975 static const struct message WmInvalidateParentChild2[] = {
4976     { WM_ERASEBKGND, sent|parent },
4977     { WM_NCPAINT, sent },
4978     { WM_GETTEXT, sent|defwinproc|optional },
4979     { WM_ERASEBKGND, sent },
4980     { 0 }
4981 };
4982
4983 static const struct message WmParentPaint[] = {
4984     { WM_PAINT, sent|parent },
4985     { WM_PAINT, sent },
4986     { 0 }
4987 };
4988
4989 static const struct message WmParentPaintNc[] = {
4990     { WM_PAINT, sent|parent },
4991     { WM_PAINT, sent },
4992     { WM_NCPAINT, sent|beginpaint },
4993     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4994     { WM_ERASEBKGND, sent|beginpaint },
4995     { 0 }
4996 };
4997
4998 static const struct message WmChildPaintNc[] = {
4999     { WM_PAINT, sent },
5000     { WM_NCPAINT, sent|beginpaint },
5001     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5002     { WM_ERASEBKGND, sent|beginpaint },
5003     { 0 }
5004 };
5005
5006 static const struct message WmParentErasePaint[] = {
5007     { WM_PAINT, sent|parent },
5008     { WM_NCPAINT, sent|parent|beginpaint },
5009     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5010     { WM_ERASEBKGND, sent|parent|beginpaint },
5011     { WM_PAINT, sent },
5012     { WM_NCPAINT, sent|beginpaint },
5013     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5014     { WM_ERASEBKGND, sent|beginpaint },
5015     { 0 }
5016 };
5017
5018 static const struct message WmParentOnlyNcPaint[] = {
5019     { WM_PAINT, sent|parent },
5020     { WM_NCPAINT, sent|parent|beginpaint },
5021     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5022     { 0 }
5023 };
5024
5025 static const struct message WmSetParentStyle[] = {
5026     { WM_STYLECHANGING, sent|parent },
5027     { WM_STYLECHANGED, sent|parent },
5028     { 0 }
5029 };
5030
5031 static void test_paint_messages(void)
5032 {
5033     BOOL ret;
5034     RECT rect;
5035     POINT pt;
5036     MSG msg;
5037     HWND hparent, hchild;
5038     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5039     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5040     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5041                                 100, 100, 200, 200, 0, 0, 0, NULL);
5042     ok (hwnd != 0, "Failed to create overlapped window\n");
5043
5044     ShowWindow( hwnd, SW_SHOW );
5045     UpdateWindow( hwnd );
5046     flush_events();
5047     flush_sequence();
5048
5049     check_update_rgn( hwnd, 0 );
5050     SetRectRgn( hrgn, 10, 10, 20, 20 );
5051     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5052     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5053     check_update_rgn( hwnd, hrgn );
5054     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5055     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5056     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5057     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5058     check_update_rgn( hwnd, hrgn );
5059     /* validate everything */
5060     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5061     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5062     check_update_rgn( hwnd, 0 );
5063
5064     /* test empty region */
5065     SetRectRgn( hrgn, 10, 10, 10, 15 );
5066     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5067     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5068     check_update_rgn( hwnd, 0 );
5069     /* test empty rect */
5070     SetRect( &rect, 10, 10, 10, 15 );
5071     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5072     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5073     check_update_rgn( hwnd, 0 );
5074
5075     /* flush pending messages */
5076     flush_events();
5077     flush_sequence();
5078
5079     GetClientRect( hwnd, &rect );
5080     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5081     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5082      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5083      */
5084     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5085     SetRectEmpty( &rect );
5086     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5087     check_update_rgn( hwnd, hrgn );
5088     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5089     flush_events();
5090     ok_sequence( WmPaint, "Paint", FALSE );
5091     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5092     check_update_rgn( hwnd, 0 );
5093
5094     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5095      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5096      */
5097     trace("testing ValidateRect(0, NULL)\n");
5098     SetRectEmpty( &rect );
5099     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
5100     check_update_rgn( hwnd, hrgn );
5101     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5102     flush_events();
5103     ok_sequence( WmPaint, "Paint", FALSE );
5104     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5105     check_update_rgn( hwnd, 0 );
5106
5107     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5108     SetLastError(0xdeadbeef);
5109     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5110     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
5111     check_update_rgn( hwnd, 0 );
5112     flush_events();
5113     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5114
5115     trace("testing ValidateRgn(0, NULL)\n");
5116     SetLastError(0xdeadbeef);
5117     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5118     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
5119     check_update_rgn( hwnd, 0 );
5120     flush_events();
5121     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5122
5123     /* now with frame */
5124     SetRectRgn( hrgn, -5, -5, 20, 20 );
5125
5126     /* flush pending messages */
5127     flush_events();
5128     flush_sequence();
5129     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5130     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5131
5132     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5133     check_update_rgn( hwnd, hrgn );
5134
5135     flush_sequence();
5136     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5137     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5138
5139     flush_sequence();
5140     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5141     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5142
5143     GetClientRect( hwnd, &rect );
5144     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5145     check_update_rgn( hwnd, hrgn );
5146
5147     flush_sequence();
5148     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5149     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5150
5151     flush_sequence();
5152     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5153     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5154     check_update_rgn( hwnd, 0 );
5155
5156     flush_sequence();
5157     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5158     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5159     check_update_rgn( hwnd, 0 );
5160
5161     flush_sequence();
5162     SetRectRgn( hrgn, 0, 0, 100, 100 );
5163     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5164     SetRectRgn( hrgn, 0, 0, 50, 100 );
5165     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5166     SetRectRgn( hrgn, 50, 0, 100, 100 );
5167     check_update_rgn( hwnd, hrgn );
5168     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5169     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5170     check_update_rgn( hwnd, 0 );
5171
5172     flush_sequence();
5173     SetRectRgn( hrgn, 0, 0, 100, 100 );
5174     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5175     SetRectRgn( hrgn, 0, 0, 100, 50 );
5176     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5177     ok_sequence( WmErase, "Erase", FALSE );
5178     SetRectRgn( hrgn, 0, 50, 100, 100 );
5179     check_update_rgn( hwnd, hrgn );
5180
5181     flush_sequence();
5182     SetRectRgn( hrgn, 0, 0, 100, 100 );
5183     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5184     SetRectRgn( hrgn, 0, 0, 50, 50 );
5185     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5186     ok_sequence( WmPaint, "Paint", FALSE );
5187
5188     flush_sequence();
5189     SetRectRgn( hrgn, -4, -4, -2, -2 );
5190     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5191     SetRectRgn( hrgn, -200, -200, -198, -198 );
5192     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5193     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5194
5195     flush_sequence();
5196     SetRectRgn( hrgn, -4, -4, -2, -2 );
5197     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5198     SetRectRgn( hrgn, -4, -4, -3, -3 );
5199     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5200     SetRectRgn( hrgn, 0, 0, 1, 1 );
5201     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5202     ok_sequence( WmPaint, "Paint", FALSE );
5203
5204     flush_sequence();
5205     SetRectRgn( hrgn, -4, -4, -1, -1 );
5206     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5207     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5208     /* make sure no WM_PAINT was generated */
5209     flush_events();
5210     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5211
5212     flush_sequence();
5213     SetRectRgn( hrgn, -4, -4, -1, -1 );
5214     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5215     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5216     {
5217         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5218         {
5219             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5220             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5221             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5222             ret = GetUpdateRect( hwnd, &rect, FALSE );
5223             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5224             /* this will send WM_NCPAINT and validate the non client area */
5225             ret = GetUpdateRect( hwnd, &rect, TRUE );
5226             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5227         }
5228         DispatchMessage( &msg );
5229     }
5230     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5231
5232     DestroyWindow( hwnd );
5233
5234     /* now test with a child window */
5235
5236     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5237                               100, 100, 200, 200, 0, 0, 0, NULL);
5238     ok (hparent != 0, "Failed to create parent window\n");
5239
5240     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5241                            10, 10, 100, 100, hparent, 0, 0, NULL);
5242     ok (hchild != 0, "Failed to create child window\n");
5243
5244     ShowWindow( hparent, SW_SHOW );
5245     UpdateWindow( hparent );
5246     UpdateWindow( hchild );
5247     flush_events();
5248     flush_sequence();
5249     log_all_parent_messages++;
5250
5251     SetRect( &rect, 0, 0, 50, 50 );
5252     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5253     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5254     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5255
5256     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5257     pt.x = pt.y = 0;
5258     MapWindowPoints( hchild, hparent, &pt, 1 );
5259     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5260     check_update_rgn( hchild, hrgn );
5261     SetRectRgn( hrgn, 0, 0, 50, 50 );
5262     check_update_rgn( hparent, hrgn );
5263     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5264     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5265     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5266     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5267
5268     flush_events();
5269     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5270
5271     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5272     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5273     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5274     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5275     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5276
5277     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5278     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5279     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5280
5281     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5282     flush_sequence();
5283     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5284     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5285     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5286
5287     /* flush all paint messages */
5288     flush_events();
5289     flush_sequence();
5290
5291     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5292     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5293     SetRectRgn( hrgn, 0, 0, 50, 50 );
5294     check_update_rgn( hparent, hrgn );
5295     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5296     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5297     SetRectRgn( hrgn, 0, 0, 50, 50 );
5298     check_update_rgn( hparent, hrgn );
5299
5300     /* flush all paint messages */
5301     flush_events();
5302     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5303     flush_sequence();
5304
5305     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5306     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5307     SetRectRgn( hrgn, 0, 0, 50, 50 );
5308     check_update_rgn( hparent, hrgn );
5309     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5310     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5311     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5312     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5313     check_update_rgn( hparent, hrgn );
5314     /* flush all paint messages */
5315     flush_events();
5316     flush_sequence();
5317
5318     /* same as above but parent gets completely validated */
5319     SetRect( &rect, 20, 20, 30, 30 );
5320     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5321     SetRectRgn( hrgn, 20, 20, 30, 30 );
5322     check_update_rgn( hparent, hrgn );
5323     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5324     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5325     check_update_rgn( hparent, 0 );  /* no update region */
5326     flush_events();
5327     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
5328
5329     /* make sure RDW_VALIDATE on child doesn't have the same effect */
5330     flush_sequence();
5331     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5332     SetRectRgn( hrgn, 20, 20, 30, 30 );
5333     check_update_rgn( hparent, hrgn );
5334     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5335     SetRectRgn( hrgn, 20, 20, 30, 30 );
5336     check_update_rgn( hparent, hrgn );
5337
5338     /* same as above but normal WM_PAINT doesn't validate parent */
5339     flush_sequence();
5340     SetRect( &rect, 20, 20, 30, 30 );
5341     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5342     SetRectRgn( hrgn, 20, 20, 30, 30 );
5343     check_update_rgn( hparent, hrgn );
5344     /* no WM_PAINT in child while parent still pending */
5345     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5346     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5347     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5348     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5349
5350     flush_sequence();
5351     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5352     /* no WM_PAINT in child while parent still pending */
5353     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5354     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5355     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5356     /* now that parent is valid child should get WM_PAINT */
5357     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5358     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5359     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5360     ok_sequence( WmEmptySeq, "No other message", FALSE );
5361
5362     /* same thing with WS_CLIPCHILDREN in parent */
5363     flush_sequence();
5364     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5365     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5366     /* changing style invalidates non client area, but we need to invalidate something else to see it */
5367     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5368     ok_sequence( WmEmptySeq, "No message", FALSE );
5369     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5370     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5371
5372     flush_sequence();
5373     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5374     SetRectRgn( hrgn, 20, 20, 30, 30 );
5375     check_update_rgn( hparent, hrgn );
5376     /* no WM_PAINT in child while parent still pending */
5377     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5378     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5379     /* WM_PAINT in parent first */
5380     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5381     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5382
5383     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5384     flush_sequence();
5385     SetRect( &rect, 0, 0, 30, 30 );
5386     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5387     SetRectRgn( hrgn, 0, 0, 30, 30 );
5388     check_update_rgn( hparent, hrgn );
5389     flush_events();
5390     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5391
5392     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5393     flush_sequence();
5394     SetRect( &rect, -10, 0, 30, 30 );
5395     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5396     SetRect( &rect, 0, 0, 20, 20 );
5397     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5398     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5399     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5400
5401     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5402     flush_sequence();
5403     SetRect( &rect, -10, 0, 30, 30 );
5404     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5405     SetRect( &rect, 0, 0, 100, 100 );
5406     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5407     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5408     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5409     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5410     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5411
5412     /* test RDW_INTERNALPAINT behavior */
5413
5414     flush_sequence();
5415     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5416     flush_events();
5417     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5418
5419     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5420     flush_events();
5421     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5422
5423     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5424     flush_events();
5425     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5426
5427     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5428     UpdateWindow( hparent );
5429     flush_events();
5430     flush_sequence();
5431     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5432     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5433     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5434                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5435     flush_events();
5436     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5437
5438     UpdateWindow( hparent );
5439     flush_events();
5440     flush_sequence();
5441     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5442     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5443     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5444                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5445     flush_events();
5446     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5447
5448     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5449     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5450     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5451     flush_events();
5452     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5453
5454     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5455     UpdateWindow( hparent );
5456     flush_events();
5457     flush_sequence();
5458     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5459     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5460     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5461                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5462     flush_events();
5463     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5464
5465     UpdateWindow( hparent );
5466     flush_events();
5467     flush_sequence();
5468     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5469     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5470     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5471                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5472     flush_events();
5473     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5474
5475     log_all_parent_messages--;
5476     DestroyWindow( hparent );
5477     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
5478
5479     DeleteObject( hrgn );
5480     DeleteObject( hrgn2 );
5481 }
5482
5483 struct wnd_event
5484 {
5485     HWND hwnd;
5486     HANDLE event;
5487 };
5488
5489 static DWORD WINAPI thread_proc(void *param)
5490 {
5491     MSG msg;
5492     struct wnd_event *wnd_event = (struct wnd_event *)param;
5493
5494     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
5495                                       100, 100, 200, 200, 0, 0, 0, NULL);
5496     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
5497
5498     SetEvent(wnd_event->event);
5499
5500     while (GetMessage(&msg, 0, 0, 0))
5501     {
5502         TranslateMessage(&msg);
5503         DispatchMessage(&msg);
5504     }
5505
5506     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
5507
5508     return 0;
5509 }
5510
5511 static void test_interthread_messages(void)
5512 {
5513     HANDLE hThread;
5514     DWORD tid;
5515     WNDPROC proc;
5516     MSG msg;
5517     char buf[256];
5518     int len, expected_len;
5519     struct wnd_event wnd_event;
5520     BOOL ret;
5521
5522     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
5523     if (!wnd_event.event)
5524     {
5525         trace("skipping interthread message test under win9x\n");
5526         return;
5527     }
5528
5529     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
5530     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
5531
5532     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5533
5534     CloseHandle(wnd_event.event);
5535
5536     SetLastError(0xdeadbeef);
5537     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
5538     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %d\n", GetLastError());
5539
5540     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5541     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
5542
5543     expected_len = lstrlenA("window caption text");
5544     memset(buf, 0, sizeof(buf));
5545     SetLastError(0xdeadbeef);
5546     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
5547     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
5548     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
5549
5550     msg.hwnd = wnd_event.hwnd;
5551     msg.message = WM_GETTEXT;
5552     msg.wParam = sizeof(buf);
5553     msg.lParam = (LPARAM)buf;
5554     memset(buf, 0, sizeof(buf));
5555     SetLastError(0xdeadbeef);
5556     len = DispatchMessageA(&msg);
5557     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
5558        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
5559
5560     /* the following test causes an exception in user.exe under win9x */
5561     msg.hwnd = wnd_event.hwnd;
5562     msg.message = WM_TIMER;
5563     msg.wParam = 0;
5564     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
5565     SetLastError(0xdeadbeef);
5566     len = DispatchMessageA(&msg);
5567     ok(!len && GetLastError() == 0xdeadbeef,
5568        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
5569
5570     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
5571     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
5572
5573     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5574     CloseHandle(hThread);
5575
5576     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
5577 }
5578
5579
5580 static const struct message WmVkN[] = {
5581     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5582     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5583     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5584     { WM_CHAR, wparam|lparam, 'n', 1 },
5585     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
5586     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5587     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5588     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5589     { 0 }
5590 };
5591 static const struct message WmShiftVkN[] = {
5592     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5593     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5594     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5595     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5596     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5597     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5598     { WM_CHAR, wparam|lparam, 'N', 1 },
5599     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
5600     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5601     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5602     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5603     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5604     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5605     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5606     { 0 }
5607 };
5608 static const struct message WmCtrlVkN[] = {
5609     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5610     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5611     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5612     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5613     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5614     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
5615     { WM_CHAR, wparam|lparam, 0x000e, 1 },
5616     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5617     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5618     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5619     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5620     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5621     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5622     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5623     { 0 }
5624 };
5625 static const struct message WmCtrlVkN_2[] = {
5626     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5627     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5628     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5629     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5630     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5631     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
5632     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5633     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5634     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5635     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5636     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5637     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5638     { 0 }
5639 };
5640 static const struct message WmAltVkN[] = {
5641     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5642     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5643     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5644     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5645     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5646     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5647     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
5648     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
5649     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
5650     { HCBT_SYSCOMMAND, hook },
5651     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5652     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5653     { 0x00AE, sent|defwinproc|optional }, /* XP */
5654     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
5655     { WM_INITMENU, sent|defwinproc },
5656     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5657     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
5658     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5659     { WM_CAPTURECHANGED, sent|defwinproc },
5660     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
5661     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5662     { WM_EXITMENULOOP, sent|defwinproc },
5663     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
5664     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
5665     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5666     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5667     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5668     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5669     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5670     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5671     { 0 }
5672 };
5673 static const struct message WmAltVkN_2[] = {
5674     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5675     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5676     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5677     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5678     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
5679     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
5680     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5681     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
5682     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5683     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5684     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5685     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5686     { 0 }
5687 };
5688 static const struct message WmCtrlAltVkN[] = {
5689     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5690     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5691     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5692     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5693     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5694     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5695     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5696     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5697     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
5698     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5699     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5700     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5701     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5702     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5703     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5704     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5705     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5706     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5707     { 0 }
5708 };
5709 static const struct message WmCtrlShiftVkN[] = {
5710     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5711     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5712     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5713     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
5714     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
5715     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
5716     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
5717     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
5718     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
5719     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
5720     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
5721     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
5722     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
5723     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
5724     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
5725     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5726     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5727     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5728     { 0 }
5729 };
5730 static const struct message WmCtrlAltShiftVkN[] = {
5731     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
5732     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
5733     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
5734     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5735     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5736     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5737     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
5738     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
5739     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
5740     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
5741     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
5742     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
5743     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
5744     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
5745     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
5746     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
5747     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
5748     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
5749     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5750     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5751     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5752     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
5753     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
5754     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
5755     { 0 }
5756 };
5757 static const struct message WmAltPressRelease[] = {
5758     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5759     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5760     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5761     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5762     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5763     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5764     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
5765     { HCBT_SYSCOMMAND, hook },
5766     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
5767     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5768     { WM_INITMENU, sent|defwinproc },
5769     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5770     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
5771     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
5772
5773     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
5774
5775     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5776     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
5777     { WM_CAPTURECHANGED, sent|defwinproc },
5778     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
5779     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
5780     { WM_EXITMENULOOP, sent|defwinproc },
5781     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5782     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5783     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5784     { 0 }
5785 };
5786 static const struct message WmAltMouseButton[] = {
5787     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
5788     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
5789     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
5790     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
5791     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
5792     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
5793     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
5794     { WM_LBUTTONUP, wparam, 0, 0 },
5795     { WM_LBUTTONUP, sent|wparam, 0, 0 },
5796     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
5797     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
5798     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
5799     { 0 }
5800 };
5801 static const struct message WmF1Seq[] = {
5802     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
5803     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
5804     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
5805     { 0x4d, wparam|lparam, 0, 0 },
5806     { 0x4d, sent|wparam|lparam, 0, 0 },
5807     { WM_HELP, sent|defwinproc },
5808     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
5809     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
5810     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
5811     { 0 }
5812 };
5813 static const struct message WmVkAppsSeq[] = {
5814     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
5815     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
5816     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
5817     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
5818     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
5819     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
5820     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
5821     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
5822     { 0 }
5823 };
5824
5825 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
5826 {
5827     MSG msg;
5828
5829     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
5830     {
5831         struct message log_msg;
5832
5833         trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
5834
5835         /* ignore some unwanted messages */
5836         if (msg.message == WM_MOUSEMOVE ||
5837             msg.message == WM_GETICON ||
5838             msg.message == WM_DEVICECHANGE)
5839             continue;
5840
5841         log_msg.message = msg.message;
5842         log_msg.flags = wparam|lparam;
5843         log_msg.wParam = msg.wParam;
5844         log_msg.lParam = msg.lParam;
5845         add_message(&log_msg);
5846
5847         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
5848         {
5849             TranslateMessage(&msg);
5850             DispatchMessage(&msg);
5851         }
5852     }
5853 }
5854
5855 static void test_accelerators(void)
5856 {
5857     RECT rc;
5858     SHORT state;
5859     HACCEL hAccel;
5860     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5861                                 100, 100, 200, 200, 0, 0, 0, NULL);
5862     BOOL ret;
5863
5864     assert(hwnd != 0);
5865     UpdateWindow(hwnd);
5866     flush_events();
5867     flush_sequence();
5868
5869     SetFocus(hwnd);
5870     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
5871
5872     state = GetKeyState(VK_SHIFT);
5873     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
5874     state = GetKeyState(VK_CAPITAL);
5875     ok(state == 0, "wrong CapsLock state %04x\n", state);
5876
5877     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
5878     assert(hAccel != 0);
5879
5880     pump_msg_loop(hwnd, 0);
5881     flush_sequence();
5882
5883     trace("testing VK_N press/release\n");
5884     flush_sequence();
5885     keybd_event('N', 0, 0, 0);
5886     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5887     pump_msg_loop(hwnd, hAccel);
5888     ok_sequence(WmVkN, "VK_N press/release", FALSE);
5889
5890     trace("testing Shift+VK_N press/release\n");
5891     flush_sequence();
5892     keybd_event(VK_SHIFT, 0, 0, 0);
5893     keybd_event('N', 0, 0, 0);
5894     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5895     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5896     pump_msg_loop(hwnd, hAccel);
5897     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5898
5899     trace("testing Ctrl+VK_N press/release\n");
5900     flush_sequence();
5901     keybd_event(VK_CONTROL, 0, 0, 0);
5902     keybd_event('N', 0, 0, 0);
5903     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5904     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5905     pump_msg_loop(hwnd, hAccel);
5906     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
5907
5908     trace("testing Alt+VK_N press/release\n");
5909     flush_sequence();
5910     keybd_event(VK_MENU, 0, 0, 0);
5911     keybd_event('N', 0, 0, 0);
5912     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5913     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5914     pump_msg_loop(hwnd, hAccel);
5915     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
5916
5917     trace("testing Ctrl+Alt+VK_N press/release 1\n");
5918     flush_sequence();
5919     keybd_event(VK_CONTROL, 0, 0, 0);
5920     keybd_event(VK_MENU, 0, 0, 0);
5921     keybd_event('N', 0, 0, 0);
5922     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5923     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5924     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5925     pump_msg_loop(hwnd, hAccel);
5926     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
5927
5928     ret = DestroyAcceleratorTable(hAccel);
5929     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
5930
5931     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
5932     assert(hAccel != 0);
5933
5934     trace("testing VK_N press/release\n");
5935     flush_sequence();
5936     keybd_event('N', 0, 0, 0);
5937     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5938     pump_msg_loop(hwnd, hAccel);
5939     ok_sequence(WmVkN, "VK_N press/release", FALSE);
5940
5941     trace("testing Shift+VK_N press/release\n");
5942     flush_sequence();
5943     keybd_event(VK_SHIFT, 0, 0, 0);
5944     keybd_event('N', 0, 0, 0);
5945     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5946     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5947     pump_msg_loop(hwnd, hAccel);
5948     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
5949
5950     trace("testing Ctrl+VK_N press/release 2\n");
5951     flush_sequence();
5952     keybd_event(VK_CONTROL, 0, 0, 0);
5953     keybd_event('N', 0, 0, 0);
5954     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5955     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5956     pump_msg_loop(hwnd, hAccel);
5957     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
5958
5959     trace("testing Alt+VK_N press/release 2\n");
5960     flush_sequence();
5961     keybd_event(VK_MENU, 0, 0, 0);
5962     keybd_event('N', 0, 0, 0);
5963     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5964     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5965     pump_msg_loop(hwnd, hAccel);
5966     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
5967
5968     trace("testing Ctrl+Alt+VK_N press/release 2\n");
5969     flush_sequence();
5970     keybd_event(VK_CONTROL, 0, 0, 0);
5971     keybd_event(VK_MENU, 0, 0, 0);
5972     keybd_event('N', 0, 0, 0);
5973     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5974     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5975     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5976     pump_msg_loop(hwnd, hAccel);
5977     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
5978
5979     trace("testing Ctrl+Shift+VK_N press/release\n");
5980     flush_sequence();
5981     keybd_event(VK_CONTROL, 0, 0, 0);
5982     keybd_event(VK_SHIFT, 0, 0, 0);
5983     keybd_event('N', 0, 0, 0);
5984     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5985     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5986     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
5987     pump_msg_loop(hwnd, hAccel);
5988     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
5989
5990     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
5991     flush_sequence();
5992     keybd_event(VK_CONTROL, 0, 0, 0);
5993     keybd_event(VK_MENU, 0, 0, 0);
5994     keybd_event(VK_SHIFT, 0, 0, 0);
5995     keybd_event('N', 0, 0, 0);
5996     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
5997     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
5998     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
5999     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6000     pump_msg_loop(hwnd, hAccel);
6001     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6002
6003     ret = DestroyAcceleratorTable(hAccel);
6004     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6005
6006     trace("testing Alt press/release\n");
6007     flush_sequence();
6008     keybd_event(VK_MENU, 0, 0, 0);
6009     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6010     keybd_event(VK_MENU, 0, 0, 0);
6011     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6012     pump_msg_loop(hwnd, 0);
6013     /* this test doesn't pass in Wine for managed windows */
6014     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6015
6016     trace("testing Alt+MouseButton press/release\n");
6017     /* first, move mouse pointer inside of the window client area */
6018     GetClientRect(hwnd, &rc);
6019     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6020     rc.left += (rc.right - rc.left)/2;
6021     rc.top += (rc.bottom - rc.top)/2;
6022     SetCursorPos(rc.left, rc.top);
6023
6024     flush_events();
6025     flush_sequence();
6026     keybd_event(VK_MENU, 0, 0, 0);
6027     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6028     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6029     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6030     pump_msg_loop(hwnd, 0);
6031     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
6032
6033     trace("testing VK_F1 press/release\n");
6034     keybd_event(VK_F1, 0, 0, 0);
6035     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6036     pump_msg_loop(hwnd, 0);
6037     ok_sequence(WmF1Seq, "F1 press/release", TRUE);
6038
6039     trace("testing VK_APPS press/release\n");
6040     keybd_event(VK_APPS, 0, 0, 0);
6041     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6042     pump_msg_loop(hwnd, 0);
6043     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6044
6045     DestroyWindow(hwnd);
6046 }
6047
6048 /************* window procedures ********************/
6049
6050 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6051                              WPARAM wParam, LPARAM lParam)
6052 {
6053     static long defwndproc_counter = 0;
6054     static long beginpaint_counter = 0;
6055     LRESULT ret;
6056     struct message msg;
6057
6058     trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6059
6060     /* explicitly ignore WM_GETICON message */
6061     if (message == WM_GETICON) return 0;
6062
6063     switch (message)
6064     {
6065         case WM_ENABLE:
6066         {
6067             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6068             ok((BOOL)wParam == !(style & WS_DISABLED),
6069                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6070             break;
6071         }
6072
6073         case WM_CAPTURECHANGED:
6074             if (test_DestroyWindow_flag)
6075             {
6076                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6077                 if (style & WS_CHILD)
6078                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6079                 else if (style & WS_POPUP)
6080                     lParam = WND_POPUP_ID;
6081                 else
6082                     lParam = WND_PARENT_ID;
6083             }
6084             break;
6085
6086         case WM_NCDESTROY:
6087         {
6088             HWND capture;
6089
6090             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6091             capture = GetCapture();
6092             if (capture)
6093             {
6094                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6095                 trace("current capture %p, releasing...\n", capture);
6096                 ReleaseCapture();
6097             }
6098         }
6099         /* fall through */
6100         case WM_DESTROY:
6101             if (pGetAncestor)
6102                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6103             if (test_DestroyWindow_flag)
6104             {
6105                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6106                 if (style & WS_CHILD)
6107                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6108                 else if (style & WS_POPUP)
6109                     lParam = WND_POPUP_ID;
6110                 else
6111                     lParam = WND_PARENT_ID;
6112             }
6113             break;
6114
6115         /* test_accelerators() depends on this */
6116         case WM_NCHITTEST:
6117             return HTCLIENT;
6118     
6119         /* ignore */
6120         case WM_MOUSEMOVE:
6121         case WM_SETCURSOR:
6122         case WM_DEVICECHANGE:
6123             return 0;
6124
6125         case WM_WINDOWPOSCHANGING:
6126         case WM_WINDOWPOSCHANGED:
6127         {
6128             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6129
6130             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6131             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6132                   winpos->hwnd, winpos->hwndInsertAfter,
6133                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6134             dump_winpos_flags(winpos->flags);
6135
6136             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6137              * in the high word for internal purposes
6138              */
6139             wParam = winpos->flags & 0xffff;
6140             /* We are not interested in the flags that don't match under XP and Win9x */
6141             wParam &= ~(SWP_NOZORDER);
6142             break;
6143         }
6144     }
6145
6146     msg.message = message;
6147     msg.flags = sent|wparam|lparam;
6148     if (defwndproc_counter) msg.flags |= defwinproc;
6149     if (beginpaint_counter) msg.flags |= beginpaint;
6150     msg.wParam = wParam;
6151     msg.lParam = lParam;
6152     add_message(&msg);
6153
6154     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6155     {
6156         HWND parent = GetParent(hwnd);
6157         RECT rc;
6158         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6159
6160         GetClientRect(parent, &rc);
6161         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6162
6163         trace("ptReserved = (%d,%d)\n"
6164               "ptMaxSize = (%d,%d)\n"
6165               "ptMaxPosition = (%d,%d)\n"
6166               "ptMinTrackSize = (%d,%d)\n"
6167               "ptMaxTrackSize = (%d,%d)\n",
6168               minmax->ptReserved.x, minmax->ptReserved.y,
6169               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6170               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6171               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6172               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6173
6174         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6175            minmax->ptMaxSize.x, rc.right);
6176         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6177            minmax->ptMaxSize.y, rc.bottom);
6178     }
6179
6180     if (message == WM_PAINT)
6181     {
6182         PAINTSTRUCT ps;
6183         beginpaint_counter++;
6184         BeginPaint( hwnd, &ps );
6185         beginpaint_counter--;
6186         EndPaint( hwnd, &ps );
6187         return 0;
6188     }
6189
6190     defwndproc_counter++;
6191     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
6192                   : DefWindowProcA(hwnd, message, wParam, lParam);
6193     defwndproc_counter--;
6194
6195     return ret;
6196 }
6197
6198 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6199 {
6200     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6201 }
6202
6203 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6204 {
6205     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6206 }
6207
6208 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6209 {
6210     static long defwndproc_counter = 0;
6211     LRESULT ret;
6212     struct message msg;
6213
6214     trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6215
6216     /* explicitly ignore WM_GETICON message */
6217     if (message == WM_GETICON) return 0;
6218
6219     msg.message = message;
6220     msg.flags = sent|wparam|lparam;
6221     if (defwndproc_counter) msg.flags |= defwinproc;
6222     msg.wParam = wParam;
6223     msg.lParam = lParam;
6224     add_message(&msg);
6225
6226     if (message == WM_CREATE)
6227     {
6228         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6229         SetWindowLongA(hwnd, GWL_STYLE, style);
6230     }
6231
6232     defwndproc_counter++;
6233     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6234     defwndproc_counter--;
6235
6236     return ret;
6237 }
6238
6239 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6240 {
6241     static long defwndproc_counter = 0;
6242     static long beginpaint_counter = 0;
6243     LRESULT ret;
6244     struct message msg;
6245
6246     trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6247
6248     /* explicitly ignore WM_GETICON message */
6249     if (message == WM_GETICON) return 0;
6250
6251     if (log_all_parent_messages ||
6252         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6253         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6254         message == WM_ENABLE || message == WM_ENTERIDLE ||
6255         message == WM_DRAWITEM ||
6256         message == WM_IME_SETCONTEXT)
6257     {
6258         switch (message)
6259         {
6260             /* ignore */
6261             case WM_NCHITTEST:
6262                 return HTCLIENT;
6263             case WM_SETCURSOR:
6264             case WM_MOUSEMOVE:
6265                 return 0;
6266
6267             case WM_ERASEBKGND:
6268             {
6269                 RECT rc;
6270                 INT ret = GetClipBox((HDC)wParam, &rc);
6271
6272                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6273                        ret, rc.left, rc.top, rc.right, rc.bottom);
6274                 break;
6275             }
6276
6277             case WM_WINDOWPOSCHANGING:
6278             case WM_WINDOWPOSCHANGED:
6279             {
6280                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6281
6282                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6283                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6284                       winpos->hwnd, winpos->hwndInsertAfter,
6285                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6286                 dump_winpos_flags(winpos->flags);
6287
6288                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6289                  * in the high word for internal purposes
6290                  */
6291                 wParam = winpos->flags & 0xffff;
6292                 /* We are not interested in the flags that don't match under XP and Win9x */
6293                 wParam &= ~(SWP_NOZORDER);
6294                 break;
6295             }
6296
6297             case WM_DRAWITEM:
6298             {
6299                 /* encode DRAWITEMSTRUCT into an LPARAM */
6300                 DRAW_ITEM_STRUCT di;
6301                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
6302
6303                 trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n",
6304                       dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState);
6305
6306                 di.u.item.type = dis->CtlType;
6307                 di.u.item.ctl_id = dis->CtlID;
6308                 di.u.item.item_id = dis->itemID;
6309                 di.u.item.action = dis->itemAction;
6310                 di.u.item.state = dis->itemState;
6311
6312                 lParam = di.u.lp;
6313                 break;
6314             }
6315         }
6316
6317         msg.message = message;
6318         msg.flags = sent|parent|wparam|lparam;
6319         if (defwndproc_counter) msg.flags |= defwinproc;
6320         if (beginpaint_counter) msg.flags |= beginpaint;
6321         msg.wParam = wParam;
6322         msg.lParam = lParam;
6323         add_message(&msg);
6324     }
6325
6326     if (message == WM_PAINT)
6327     {
6328         PAINTSTRUCT ps;
6329         beginpaint_counter++;
6330         BeginPaint( hwnd, &ps );
6331         beginpaint_counter--;
6332         EndPaint( hwnd, &ps );
6333         return 0;
6334     }
6335
6336     defwndproc_counter++;
6337     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6338     defwndproc_counter--;
6339
6340     return ret;
6341 }
6342
6343 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6344 {
6345     static long defwndproc_counter = 0;
6346     LRESULT ret;
6347     struct message msg;
6348
6349     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6350
6351     /* explicitly ignore WM_GETICON message */
6352     if (message == WM_GETICON) return 0;
6353
6354     if (test_def_id)
6355     {
6356         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6357         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6358         if (after_end_dialog)
6359             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6360         else
6361             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6362     }
6363
6364     switch (message)
6365     {
6366         case WM_WINDOWPOSCHANGING:
6367         case WM_WINDOWPOSCHANGED:
6368         {
6369             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6370
6371             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6372             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6373                   winpos->hwnd, winpos->hwndInsertAfter,
6374                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6375             dump_winpos_flags(winpos->flags);
6376
6377             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6378              * in the high word for internal purposes
6379              */
6380             wParam = winpos->flags & 0xffff;
6381             /* We are not interested in the flags that don't match under XP and Win9x */
6382             wParam &= ~(SWP_NOZORDER);
6383             break;
6384         }
6385     }
6386
6387     msg.message = message;
6388     msg.flags = sent|wparam|lparam;
6389     if (defwndproc_counter) msg.flags |= defwinproc;
6390     msg.wParam = wParam;
6391     msg.lParam = lParam;
6392     add_message(&msg);
6393
6394     defwndproc_counter++;
6395     ret = DefDlgProcA(hwnd, message, wParam, lParam);
6396     defwndproc_counter--;
6397
6398     return ret;
6399 }
6400
6401 static void dump_winpos_flags(UINT flags)
6402 {
6403     if (!winetest_debug) return;
6404
6405     if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
6406     if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
6407     if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
6408     if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
6409     if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
6410     if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
6411     if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
6412     if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
6413     if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
6414     if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
6415     if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
6416     if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
6417     if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
6418     if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
6419     if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
6420
6421 #define DUMPED_FLAGS \
6422     (SWP_NOSIZE | \
6423     SWP_NOMOVE | \
6424     SWP_NOZORDER | \
6425     SWP_NOREDRAW | \
6426     SWP_NOACTIVATE | \
6427     SWP_FRAMECHANGED | \
6428     SWP_SHOWWINDOW | \
6429     SWP_HIDEWINDOW | \
6430     SWP_NOCOPYBITS | \
6431     SWP_NOOWNERZORDER | \
6432     SWP_NOSENDCHANGING | \
6433     SWP_DEFERERASE | \
6434     SWP_ASYNCWINDOWPOS | \
6435     SWP_NOCLIENTSIZE | \
6436     SWP_NOCLIENTMOVE)
6437
6438     if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
6439     printf("\n");
6440 #undef DUMPED_FLAGS
6441 }
6442
6443 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6444 {
6445     static long defwndproc_counter = 0;
6446     LRESULT ret;
6447     struct message msg;
6448
6449     /* log only specific messages we are interested in */
6450     switch (message)
6451     {
6452 #if 0 /* probably log these as well */
6453     case WM_ACTIVATE:
6454     case WM_SETFOCUS:
6455     case WM_KILLFOCUS:
6456 #endif
6457     case WM_SHOWWINDOW:
6458         trace("WM_SHOWWINDOW %ld\n", wParam);
6459         break;
6460     case WM_SIZE:
6461         trace("WM_SIZE %ld\n", wParam);
6462         break;
6463     case WM_MOVE:
6464         trace("WM_MOVE\n");
6465         break;
6466     case WM_GETMINMAXINFO:
6467         trace("WM_GETMINMAXINFO\n");
6468         break;
6469
6470     case WM_WINDOWPOSCHANGING:
6471     case WM_WINDOWPOSCHANGED:
6472     {
6473         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6474
6475         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6476         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
6477               winpos->hwnd, winpos->hwndInsertAfter,
6478               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6479         trace("flags: ");
6480         dump_winpos_flags(winpos->flags);
6481
6482         /* Log only documented flags, win2k uses 0x1000 and 0x2000
6483          * in the high word for internal purposes
6484          */
6485         wParam = winpos->flags & 0xffff;
6486         /* We are not interested in the flags that don't match under XP and Win9x */
6487         wParam &= ~(SWP_NOZORDER);
6488         break;
6489     }
6490
6491     default: /* ignore */
6492         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
6493         return DefWindowProcA(hwnd, message, wParam, lParam);
6494     }
6495
6496     msg.message = message;
6497     msg.flags = sent|wparam|lparam;
6498     if (defwndproc_counter) msg.flags |= defwinproc;
6499     msg.wParam = wParam;
6500     msg.lParam = lParam;
6501     add_message(&msg);
6502
6503     defwndproc_counter++;
6504     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6505     defwndproc_counter--;
6506
6507     return ret;
6508 }
6509
6510 static BOOL RegisterWindowClasses(void)
6511 {
6512     WNDCLASSA cls;
6513     WNDCLASSW clsW;
6514
6515     cls.style = 0;
6516     cls.lpfnWndProc = MsgCheckProcA;
6517     cls.cbClsExtra = 0;
6518     cls.cbWndExtra = 0;
6519     cls.hInstance = GetModuleHandleA(0);
6520     cls.hIcon = 0;
6521     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
6522     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
6523     cls.lpszMenuName = NULL;
6524     cls.lpszClassName = "TestWindowClass";
6525     if(!RegisterClassA(&cls)) return FALSE;
6526
6527     cls.lpfnWndProc = ShowWindowProcA;
6528     cls.lpszClassName = "ShowWindowClass";
6529     if(!RegisterClassA(&cls)) return FALSE;
6530
6531     cls.lpfnWndProc = PopupMsgCheckProcA;
6532     cls.lpszClassName = "TestPopupClass";
6533     if(!RegisterClassA(&cls)) return FALSE;
6534
6535     cls.lpfnWndProc = ParentMsgCheckProcA;
6536     cls.lpszClassName = "TestParentClass";
6537     if(!RegisterClassA(&cls)) return FALSE;
6538
6539     cls.lpfnWndProc = DefWindowProcA;
6540     cls.lpszClassName = "SimpleWindowClass";
6541     if(!RegisterClassA(&cls)) return FALSE;
6542
6543     cls.style = CS_NOCLOSE;
6544     cls.lpszClassName = "NoCloseWindowClass";
6545     if(!RegisterClassA(&cls)) return FALSE;
6546
6547     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
6548     cls.style = 0;
6549     cls.hInstance = GetModuleHandleA(0);
6550     cls.hbrBackground = 0;
6551     cls.lpfnWndProc = TestDlgProcA;
6552     cls.lpszClassName = "TestDialogClass";
6553     if(!RegisterClassA(&cls)) return FALSE;
6554
6555     clsW.style = 0;
6556     clsW.lpfnWndProc = MsgCheckProcW;
6557     clsW.cbClsExtra = 0;
6558     clsW.cbWndExtra = 0;
6559     clsW.hInstance = GetModuleHandleW(0);
6560     clsW.hIcon = 0;
6561     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
6562     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
6563     clsW.lpszMenuName = NULL;
6564     clsW.lpszClassName = testWindowClassW;
6565     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
6566
6567     return TRUE;
6568 }
6569
6570 static HHOOK hCBT_hook;
6571 static DWORD cbt_hook_thread_id;
6572
6573 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
6574
6575     static const char * const CBT_code_name[10] = {
6576         "HCBT_MOVESIZE",
6577         "HCBT_MINMAX",
6578         "HCBT_QS",
6579         "HCBT_CREATEWND",
6580         "HCBT_DESTROYWND",
6581         "HCBT_ACTIVATE",
6582         "HCBT_CLICKSKIPPED",
6583         "HCBT_KEYSKIPPED",
6584         "HCBT_SYSCOMMAND",
6585         "HCBT_SETFOCUS" };
6586     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
6587     HWND hwnd;
6588     char buf[256];
6589
6590     trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
6591
6592     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6593
6594     if (nCode == HCBT_CLICKSKIPPED)
6595     {
6596         /* ignore this event, XP sends it a lot when switching focus between windows */
6597         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6598     }
6599
6600     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
6601     {
6602         struct message msg;
6603
6604         msg.message = nCode;
6605         msg.flags = hook|wparam|lparam;
6606         msg.wParam = wParam;
6607         msg.lParam = lParam;
6608         add_message(&msg);
6609
6610         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6611     }
6612
6613     if (nCode == HCBT_DESTROYWND)
6614     {
6615         if (test_DestroyWindow_flag)
6616         {
6617             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
6618             if (style & WS_CHILD)
6619                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
6620             else if (style & WS_POPUP)
6621                 lParam = WND_POPUP_ID;
6622             else
6623                 lParam = WND_PARENT_ID;
6624         }
6625     }
6626
6627     /* Log also SetFocus(0) calls */
6628     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
6629
6630     if (GetClassNameA(hwnd, buf, sizeof(buf)))
6631     {
6632         if (!lstrcmpiA(buf, "TestWindowClass") ||
6633             !lstrcmpiA(buf, "ShowWindowClass") ||
6634             !lstrcmpiA(buf, "TestParentClass") ||
6635             !lstrcmpiA(buf, "TestPopupClass") ||
6636             !lstrcmpiA(buf, "SimpleWindowClass") ||
6637             !lstrcmpiA(buf, "TestDialogClass") ||
6638             !lstrcmpiA(buf, "MDI_frame_class") ||
6639             !lstrcmpiA(buf, "MDI_client_class") ||
6640             !lstrcmpiA(buf, "MDI_child_class") ||
6641             !lstrcmpiA(buf, "my_button_class") ||
6642             !lstrcmpiA(buf, "my_edit_class") ||
6643             !lstrcmpiA(buf, "static") ||
6644             !lstrcmpiA(buf, "ListBox") ||
6645             !lstrcmpiA(buf, "MyDialogClass") ||
6646             !lstrcmpiA(buf, "#32770"))
6647         {
6648             struct message msg;
6649
6650             msg.message = nCode;
6651             msg.flags = hook|wparam|lparam;
6652             msg.wParam = wParam;
6653             msg.lParam = lParam;
6654             add_message(&msg);
6655         }
6656     }
6657     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
6658 }
6659
6660 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
6661                                     DWORD event,
6662                                     HWND hwnd,
6663                                     LONG object_id,
6664                                     LONG child_id,
6665                                     DWORD thread_id,
6666                                     DWORD event_time)
6667 {
6668     char buf[256];
6669
6670     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
6671            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
6672
6673     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
6674
6675     /* ignore mouse cursor events */
6676     if (object_id == OBJID_CURSOR) return;
6677
6678     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
6679     {
6680         if (!hwnd ||
6681             !lstrcmpiA(buf, "TestWindowClass") ||
6682             !lstrcmpiA(buf, "TestParentClass") ||
6683             !lstrcmpiA(buf, "TestPopupClass") ||
6684             !lstrcmpiA(buf, "SimpleWindowClass") ||
6685             !lstrcmpiA(buf, "TestDialogClass") ||
6686             !lstrcmpiA(buf, "MDI_frame_class") ||
6687             !lstrcmpiA(buf, "MDI_client_class") ||
6688             !lstrcmpiA(buf, "MDI_child_class") ||
6689             !lstrcmpiA(buf, "my_button_class") ||
6690             !lstrcmpiA(buf, "my_edit_class") ||
6691             !lstrcmpiA(buf, "static") ||
6692             !lstrcmpiA(buf, "ListBox") ||
6693             !lstrcmpiA(buf, "MyDialogClass") ||
6694             !lstrcmpiA(buf, "#32770"))
6695         {
6696             struct message msg;
6697
6698             msg.message = event;
6699             msg.flags = winevent_hook|wparam|lparam;
6700             msg.wParam = object_id;
6701             msg.lParam = child_id;
6702             add_message(&msg);
6703         }
6704     }
6705 }
6706
6707 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
6708 static const WCHAR wszAnsi[] = {'U',0};
6709
6710 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6711 {
6712     switch (uMsg)
6713     {
6714     case CB_FINDSTRINGEXACT:
6715         trace("String: %p\n", (LPCWSTR)lParam);
6716         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
6717             return 1;
6718         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
6719             return 0;
6720         return -1;
6721     }
6722     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
6723 }
6724
6725 static const struct message WmGetTextLengthAfromW[] = {
6726     { WM_GETTEXTLENGTH, sent },
6727     { WM_GETTEXT, sent },
6728     { 0 }
6729 };
6730
6731 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
6732
6733 /* dummy window proc for WM_GETTEXTLENGTH test */
6734 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
6735 {
6736     switch(msg)
6737     {
6738     case WM_GETTEXTLENGTH:
6739         return lstrlenW(dummy_window_text) + 37;  /* some random length */
6740     case WM_GETTEXT:
6741         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
6742         return lstrlenW( (LPWSTR)lp );
6743     default:
6744         return DefWindowProcW( hwnd, msg, wp, lp );
6745     }
6746 }
6747
6748 static void test_message_conversion(void)
6749 {
6750     static const WCHAR wszMsgConversionClass[] =
6751         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
6752     WNDCLASSW cls;
6753     LRESULT lRes;
6754     HWND hwnd;
6755     WNDPROC wndproc, newproc;
6756     BOOL ret;
6757
6758     cls.style = 0;
6759     cls.lpfnWndProc = MsgConversionProcW;
6760     cls.cbClsExtra = 0;
6761     cls.cbWndExtra = 0;
6762     cls.hInstance = GetModuleHandleW(NULL);
6763     cls.hIcon = NULL;
6764     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
6765     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
6766     cls.lpszMenuName = NULL;
6767     cls.lpszClassName = wszMsgConversionClass;
6768     /* this call will fail on Win9x, but that doesn't matter as this test is
6769      * meaningless on those platforms */
6770     if(!RegisterClassW(&cls)) return;
6771
6772     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
6773                            100, 100, 200, 200, 0, 0, 0, NULL);
6774     ok(hwnd != NULL, "Window creation failed\n");
6775
6776     /* {W, A} -> A */
6777
6778     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
6779     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6780     ok(lRes == 0, "String should have been converted\n");
6781     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6782     ok(lRes == 1, "String shouldn't have been converted\n");
6783
6784     /* {W, A} -> W */
6785
6786     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
6787     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6788     ok(lRes == 1, "String shouldn't have been converted\n");
6789     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6790     ok(lRes == 1, "String shouldn't have been converted\n");
6791
6792     /* Synchronous messages */
6793
6794     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6795     ok(lRes == 0, "String should have been converted\n");
6796     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6797     ok(lRes == 1, "String shouldn't have been converted\n");
6798
6799     /* Asynchronous messages */
6800
6801     SetLastError(0);
6802     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6803     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6804         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6805     SetLastError(0);
6806     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6807     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6808         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6809     SetLastError(0);
6810     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6811     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6812         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6813     SetLastError(0);
6814     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6815     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6816         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6817     SetLastError(0);
6818     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6819     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6820         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6821     SetLastError(0);
6822     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
6823     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6824         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6825     SetLastError(0);
6826     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6827     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6828         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6829     SetLastError(0);
6830     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
6831     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
6832         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
6833
6834     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
6835
6836     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
6837                           WS_OVERLAPPEDWINDOW,
6838                           100, 100, 200, 200, 0, 0, 0, NULL);
6839     assert(hwnd);
6840     flush_sequence();
6841     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
6842     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6843     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6844         "got bad length %ld\n", lRes );
6845
6846     flush_sequence();
6847     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
6848                             hwnd, WM_GETTEXTLENGTH, 0, 0);
6849     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
6850     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
6851         "got bad length %ld\n", lRes );
6852
6853     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
6854     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
6855     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6856     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6857                                      NULL, 0, NULL, NULL ),
6858         "got bad length %ld\n", lRes );
6859
6860     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
6861     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
6862     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
6863                                      NULL, 0, NULL, NULL ),
6864         "got bad length %ld\n", lRes );
6865
6866     ret = DestroyWindow(hwnd);
6867     ok( ret, "DestroyWindow() error %d\n", GetLastError());
6868 }
6869
6870 struct timer_info
6871 {
6872     HWND hWnd;
6873     HANDLE handles[2];
6874     DWORD id;
6875 };
6876
6877 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
6878 {
6879 }
6880
6881 #define TIMER_ID  0x19
6882
6883 static DWORD WINAPI timer_thread_proc(LPVOID x)
6884 {
6885     struct timer_info *info = x;
6886     DWORD r;
6887
6888     r = KillTimer(info->hWnd, 0x19);
6889     ok(r,"KillTimer failed in thread\n");
6890     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
6891     ok(r,"SetTimer failed in thread\n");
6892     ok(r==TIMER_ID,"SetTimer id different\n");
6893     r = SetEvent(info->handles[0]);
6894     ok(r,"SetEvent failed in thread\n");
6895     return 0;
6896 }
6897
6898 static void test_timers(void)
6899 {
6900     struct timer_info info;
6901     DWORD id;
6902
6903     info.hWnd = CreateWindow ("TestWindowClass", NULL,
6904        WS_OVERLAPPEDWINDOW ,
6905        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
6906        NULL, NULL, 0);
6907
6908     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
6909     ok(info.id, "SetTimer failed\n");
6910     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
6911     info.handles[0] = CreateEvent(NULL,0,0,NULL);
6912     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
6913
6914     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
6915
6916     WaitForSingleObject(info.handles[1], INFINITE);
6917
6918     CloseHandle(info.handles[0]);
6919     CloseHandle(info.handles[1]);
6920
6921     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
6922
6923     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
6924 }
6925
6926 static int count = 0;
6927 static VOID CALLBACK callback_count(
6928     HWND hwnd,
6929     UINT uMsg,
6930     UINT_PTR idEvent,
6931     DWORD dwTime
6932 )
6933 {
6934     count++;
6935 }
6936
6937 static void test_timers_no_wnd(void)
6938 {
6939     UINT_PTR id, id2;
6940     MSG msg;
6941
6942     count = 0;
6943     id = SetTimer(NULL, 0, 100, callback_count);
6944     ok(id != 0, "did not get id from SetTimer.\n");
6945     id2 = SetTimer(NULL, id, 200, callback_count);
6946     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
6947     Sleep(150);
6948     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6949     ok(count == 0, "did not get zero count as expected (%i).\n", count);
6950     Sleep(150);
6951     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6952     ok(count == 1, "did not get one count as expected (%i).\n", count);
6953     KillTimer(NULL, id);
6954     Sleep(250);
6955     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6956     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
6957 }
6958
6959 /* Various win events with arbitrary parameters */
6960 static const struct message WmWinEventsSeq[] = {
6961     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6962     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6963     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6964     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6965     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6966     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6967     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6968     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6969     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6970     /* our win event hook ignores OBJID_CURSOR events */
6971     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
6972     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
6973     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
6974     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
6975     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
6976     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
6977     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6978     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
6979     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
6980     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
6981     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
6982     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
6983     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
6984     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
6985     { 0 }
6986 };
6987 static const struct message WmWinEventCaretSeq[] = {
6988     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6989     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6990     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
6991     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
6992     { 0 }
6993 };
6994 static const struct message WmWinEventCaretSeq_2[] = {
6995     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6996     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6997     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
6998     { 0 }
6999 };
7000 static const struct message WmWinEventAlertSeq[] = {
7001     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7002     { 0 }
7003 };
7004 static const struct message WmWinEventAlertSeq_2[] = {
7005     /* create window in the thread proc */
7006     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7007     /* our test event */
7008     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7009     { 0 }
7010 };
7011 static const struct message WmGlobalHookSeq_1[] = {
7012     /* create window in the thread proc */
7013     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7014     /* our test events */
7015     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7016     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7017     { 0 }
7018 };
7019 static const struct message WmGlobalHookSeq_2[] = {
7020     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7021     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7022     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7023     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7024     { 0 }
7025 };
7026
7027 static const struct message WmMouseLLHookSeq[] = {
7028     { WM_MOUSEMOVE, hook },
7029     { WM_LBUTTONUP, hook },
7030     { WM_MOUSEMOVE, hook },
7031     { 0 }
7032 };
7033
7034 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7035                                          DWORD event,
7036                                          HWND hwnd,
7037                                          LONG object_id,
7038                                          LONG child_id,
7039                                          DWORD thread_id,
7040                                          DWORD event_time)
7041 {
7042     char buf[256];
7043
7044     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7045            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7046
7047     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7048     {
7049         if (!lstrcmpiA(buf, "TestWindowClass") ||
7050             !lstrcmpiA(buf, "static"))
7051         {
7052             struct message msg;
7053
7054             msg.message = event;
7055             msg.flags = winevent_hook|wparam|lparam;
7056             msg.wParam = object_id;
7057             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7058             add_message(&msg);
7059         }
7060     }
7061 }
7062
7063 static HHOOK hCBT_global_hook;
7064 static DWORD cbt_global_hook_thread_id;
7065
7066 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7067
7068     HWND hwnd;
7069     char buf[256];
7070
7071     trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
7072
7073     if (nCode == HCBT_SYSCOMMAND)
7074     {
7075         struct message msg;
7076
7077         msg.message = nCode;
7078         msg.flags = hook|wparam|lparam;
7079         msg.wParam = wParam;
7080         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7081         add_message(&msg);
7082
7083         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7084     }
7085     /* WH_MOUSE_LL hook */
7086     if (nCode == HC_ACTION)
7087     {
7088         struct message msg;
7089         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7090
7091         /* we can't test for real mouse events */
7092         if (mhll->flags & LLMHF_INJECTED)
7093         {
7094             msg.message = wParam;
7095             msg.flags = hook;
7096             add_message(&msg);
7097         }
7098         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7099     }
7100
7101     /* Log also SetFocus(0) calls */
7102     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7103
7104     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7105     {
7106         if (!lstrcmpiA(buf, "TestWindowClass") ||
7107             !lstrcmpiA(buf, "static"))
7108         {
7109             struct message msg;
7110
7111             msg.message = nCode;
7112             msg.flags = hook|wparam|lparam;
7113             msg.wParam = wParam;
7114             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7115             add_message(&msg);
7116         }
7117     }
7118     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7119 }
7120
7121 static DWORD WINAPI win_event_global_thread_proc(void *param)
7122 {
7123     HWND hwnd;
7124     MSG msg;
7125     HANDLE hevent = *(HANDLE *)param;
7126
7127     assert(pNotifyWinEvent);
7128
7129     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7130     assert(hwnd);
7131     trace("created thread window %p\n", hwnd);
7132
7133     *(HWND *)param = hwnd;
7134
7135     flush_sequence();
7136     /* this event should be received only by our new hook proc,
7137      * an old one does not expect an event from another thread.
7138      */
7139     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7140     SetEvent(hevent);
7141
7142     while (GetMessage(&msg, 0, 0, 0))
7143     {
7144         TranslateMessage(&msg);
7145         DispatchMessage(&msg);
7146     }
7147     return 0;
7148 }
7149
7150 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7151 {
7152     HWND hwnd;
7153     MSG msg;
7154     HANDLE hevent = *(HANDLE *)param;
7155
7156     flush_sequence();
7157     /* these events should be received only by our new hook proc,
7158      * an old one does not expect an event from another thread.
7159      */
7160
7161     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7162     assert(hwnd);
7163     trace("created thread window %p\n", hwnd);
7164
7165     *(HWND *)param = hwnd;
7166
7167     /* Windows doesn't like when a thread plays games with the focus,
7168        that leads to all kinds of misbehaviours and failures to activate
7169        a window. So, better keep next lines commented out.
7170     SetFocus(0);
7171     SetFocus(hwnd);*/
7172
7173     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7174     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7175
7176     SetEvent(hevent);
7177
7178     while (GetMessage(&msg, 0, 0, 0))
7179     {
7180         TranslateMessage(&msg);
7181         DispatchMessage(&msg);
7182     }
7183     return 0;
7184 }
7185
7186 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7187 {
7188     HWND hwnd;
7189     MSG msg;
7190     HANDLE hevent = *(HANDLE *)param;
7191
7192     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7193     assert(hwnd);
7194     trace("created thread window %p\n", hwnd);
7195
7196     *(HWND *)param = hwnd;
7197
7198     flush_sequence();
7199
7200     /* Windows doesn't like when a thread plays games with the focus,
7201      * that leads to all kinds of misbehaviours and failures to activate
7202      * a window. So, better don't generate a mouse click message below.
7203      */
7204     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7205     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7206     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7207
7208     SetEvent(hevent);
7209     while (GetMessage(&msg, 0, 0, 0))
7210     {
7211         TranslateMessage(&msg);
7212         DispatchMessage(&msg);
7213     }
7214     return 0;
7215 }
7216
7217 static void test_winevents(void)
7218 {
7219     BOOL ret;
7220     MSG msg;
7221     HWND hwnd, hwnd2;
7222     UINT i;
7223     HANDLE hthread, hevent;
7224     DWORD tid;
7225     HWINEVENTHOOK hhook;
7226     const struct message *events = WmWinEventsSeq;
7227
7228     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7229                            WS_OVERLAPPEDWINDOW,
7230                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7231                            NULL, NULL, 0);
7232     assert(hwnd);
7233
7234     /****** start of global hook test *************/
7235     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7236     assert(hCBT_global_hook);
7237
7238     hevent = CreateEventA(NULL, 0, 0, NULL);
7239     assert(hevent);
7240     hwnd2 = (HWND)hevent;
7241
7242     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7243     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7244
7245     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7246
7247     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7248
7249     flush_sequence();
7250     /* this one should be received only by old hook proc */
7251     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7252     /* this one should be received only by old hook proc */
7253     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7254
7255     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7256
7257     ret = UnhookWindowsHookEx(hCBT_global_hook);
7258     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7259
7260     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7261     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7262     CloseHandle(hthread);
7263     CloseHandle(hevent);
7264     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7265     /****** end of global hook test *************/
7266
7267     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7268     {
7269         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7270         return;
7271     }
7272
7273     flush_sequence();
7274
7275     if (0)
7276     {
7277     /* this test doesn't pass under Win9x */
7278     /* win2k ignores events with hwnd == 0 */
7279     SetLastError(0xdeadbeef);
7280     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7281     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7282        GetLastError() == 0xdeadbeef, /* Win9x */
7283        "unexpected error %d\n", GetLastError());
7284     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7285     }
7286
7287     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7288         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7289
7290     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7291
7292     /****** start of event filtering test *************/
7293     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7294         EVENT_OBJECT_SHOW, /* 0x8002 */
7295         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7296         GetModuleHandleA(0), win_event_global_hook_proc,
7297         GetCurrentProcessId(), 0,
7298         WINEVENT_INCONTEXT);
7299     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7300
7301     hevent = CreateEventA(NULL, 0, 0, NULL);
7302     assert(hevent);
7303     hwnd2 = (HWND)hevent;
7304
7305     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7306     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7307
7308     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7309
7310     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7311
7312     flush_sequence();
7313     /* this one should be received only by old hook proc */
7314     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7315     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7316     /* this one should be received only by old hook proc */
7317     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7318
7319     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7320
7321     ret = pUnhookWinEvent(hhook);
7322     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7323
7324     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7325     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7326     CloseHandle(hthread);
7327     CloseHandle(hevent);
7328     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7329     /****** end of event filtering test *************/
7330
7331     /****** start of out of context event test *************/
7332     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7333         EVENT_MIN, EVENT_MAX,
7334         0, win_event_global_hook_proc,
7335         GetCurrentProcessId(), 0,
7336         WINEVENT_OUTOFCONTEXT);
7337     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7338
7339     hevent = CreateEventA(NULL, 0, 0, NULL);
7340     assert(hevent);
7341     hwnd2 = (HWND)hevent;
7342
7343     flush_sequence();
7344
7345     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7346     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7347
7348     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7349
7350     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7351     /* process pending winevent messages */
7352     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7353     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7354
7355     flush_sequence();
7356     /* this one should be received only by old hook proc */
7357     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7358     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7359     /* this one should be received only by old hook proc */
7360     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7361
7362     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
7363     /* process pending winevent messages */
7364     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7365     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
7366
7367     ret = pUnhookWinEvent(hhook);
7368     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7369
7370     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7371     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7372     CloseHandle(hthread);
7373     CloseHandle(hevent);
7374     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7375     /****** end of out of context event test *************/
7376
7377     /****** start of MOUSE_LL hook test *************/
7378     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7379     /* WH_MOUSE_LL is not supported on Win9x platforms */
7380     if (!hCBT_global_hook)
7381     {
7382         trace("Skipping WH_MOUSE_LL test on this platform\n");
7383         goto skip_mouse_ll_hook_test;
7384     }
7385
7386     hevent = CreateEventA(NULL, 0, 0, NULL);
7387     assert(hevent);
7388     hwnd2 = (HWND)hevent;
7389
7390     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
7391     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7392
7393     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
7394         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
7395
7396     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
7397     flush_sequence();
7398
7399     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7400     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7401     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7402
7403     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
7404
7405     ret = UnhookWindowsHookEx(hCBT_global_hook);
7406     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7407
7408     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7409     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7410     CloseHandle(hthread);
7411     CloseHandle(hevent);
7412     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7413     /****** end of MOUSE_LL hook test *************/
7414 skip_mouse_ll_hook_test:
7415
7416     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7417 }
7418
7419 static void test_set_hook(void)
7420 {
7421     BOOL ret;
7422     HHOOK hhook;
7423     HWINEVENTHOOK hwinevent_hook;
7424
7425     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
7426     ok(hhook != 0, "local hook does not require hModule set to 0\n");
7427     UnhookWindowsHookEx(hhook);
7428
7429     if (0)
7430     {
7431     /* this test doesn't pass under Win9x: BUG! */
7432     SetLastError(0xdeadbeef);
7433     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
7434     ok(!hhook, "global hook requires hModule != 0\n");
7435     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
7436     }
7437
7438     SetLastError(0xdeadbeef);
7439     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
7440     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
7441     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
7442        GetLastError() == 0xdeadbeef, /* Win9x */
7443        "unexpected error %d\n", GetLastError());
7444
7445     SetLastError(0xdeadbeef);
7446     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
7447     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
7448        GetLastError() == 0xdeadbeef, /* Win9x */
7449        "unexpected error %d\n", GetLastError());
7450
7451     if (!pSetWinEventHook || !pUnhookWinEvent) return;
7452
7453     /* even process local incontext hooks require hmodule */
7454     SetLastError(0xdeadbeef);
7455     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7456         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
7457     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7458     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7459        GetLastError() == 0xdeadbeef, /* Win9x */
7460        "unexpected error %d\n", GetLastError());
7461
7462     /* even thread local incontext hooks require hmodule */
7463     SetLastError(0xdeadbeef);
7464     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7465         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
7466     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
7467     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
7468        GetLastError() == 0xdeadbeef, /* Win9x */
7469        "unexpected error %d\n", GetLastError());
7470
7471     if (0)
7472     {
7473     /* these 3 tests don't pass under Win9x */
7474     SetLastError(0xdeadbeef);
7475     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
7476         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7477     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7478     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7479
7480     SetLastError(0xdeadbeef);
7481     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
7482         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7483     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
7484     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
7485
7486     SetLastError(0xdeadbeef);
7487     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7488         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
7489     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
7490     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
7491     }
7492
7493     SetLastError(0xdeadbeef);
7494     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
7495         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
7496     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7497     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7498     ret = pUnhookWinEvent(hwinevent_hook);
7499     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7500
7501 todo_wine {
7502     /* This call succeeds under win2k SP4, but fails under Wine.
7503        Does win2k test/use passed process id? */
7504     SetLastError(0xdeadbeef);
7505     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7506         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
7507     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
7508     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
7509     ret = pUnhookWinEvent(hwinevent_hook);
7510     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7511 }
7512
7513     SetLastError(0xdeadbeef);
7514     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
7515     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7516         GetLastError() == 0xdeadbeef, /* Win9x */
7517         "unexpected error %d\n", GetLastError());
7518 }
7519
7520 static const struct message ScrollWindowPaint1[] = {
7521     { WM_PAINT, sent },
7522     { WM_ERASEBKGND, sent|beginpaint },
7523     { 0 }
7524 };
7525
7526 static const struct message ScrollWindowPaint2[] = {
7527     { WM_PAINT, sent },
7528     { 0 }
7529 };
7530
7531 static void test_scrollwindowex(void)
7532 {
7533     HWND hwnd, hchild;
7534     RECT rect={0,0,130,130};
7535
7536     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
7537             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
7538             100, 100, 200, 200, 0, 0, 0, NULL);
7539     ok (hwnd != 0, "Failed to create overlapped window\n");
7540     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
7541             WS_VISIBLE|WS_CAPTION|WS_CHILD,
7542             10, 10, 150, 150, hwnd, 0, 0, NULL);
7543     ok (hchild != 0, "Failed to create child\n");
7544     UpdateWindow(hwnd);
7545     flush_events();
7546     flush_sequence();
7547
7548     /* scroll without the child window */
7549     trace("start scroll\n");
7550     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7551             SW_ERASE|SW_INVALIDATE);
7552     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7553     trace("end scroll\n");
7554     flush_sequence();
7555     flush_events();
7556     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7557     flush_events();
7558     flush_sequence();
7559
7560     /* Now without the SW_ERASE flag */
7561     trace("start scroll\n");
7562     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
7563     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7564     trace("end scroll\n");
7565     flush_sequence();
7566     flush_events();
7567     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
7568     flush_events();
7569     flush_sequence();
7570
7571     /* now scroll the child window as well */
7572     trace("start scroll\n");
7573     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
7574             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7575     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
7576                 /* windows sometimes a WM_MOVE */
7577         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
7578     }
7579     trace("end scroll\n");
7580     flush_sequence();
7581     flush_events();
7582     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
7583     flush_events();
7584     flush_sequence();
7585
7586     /* now scroll with ScrollWindow() */
7587     trace("start scroll with ScrollWindow\n");
7588     ScrollWindow( hwnd, 5, 5, NULL, NULL);
7589     trace("end scroll\n");
7590     flush_sequence();
7591     flush_events();
7592     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
7593
7594     ok(DestroyWindow(hchild), "failed to destroy window\n");
7595     ok(DestroyWindow(hwnd), "failed to destroy window\n");
7596     flush_sequence();
7597 }
7598
7599 static const struct message destroy_window_with_children[] = {
7600     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7601     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
7602     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
7603     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
7604     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7605     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7606     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
7607     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
7608     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7609     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7610     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7611     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7612     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
7613     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
7614     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
7615     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
7616     { 0 }
7617 };
7618
7619 static void test_DestroyWindow(void)
7620 {
7621     BOOL ret;
7622     HWND parent, child1, child2, child3, child4, test;
7623     UINT child_id = WND_CHILD_ID + 1;
7624
7625     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7626                              100, 100, 200, 200, 0, 0, 0, NULL);
7627     assert(parent != 0);
7628     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7629                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
7630     assert(child1 != 0);
7631     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7632                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
7633     assert(child2 != 0);
7634     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
7635                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
7636     assert(child3 != 0);
7637     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
7638                              0, 0, 50, 50, parent, 0, 0, NULL);
7639     assert(child4 != 0);
7640
7641     /* test owner/parent of child2 */
7642     test = GetParent(child2);
7643     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7644     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7645     if(pGetAncestor) {
7646         test = pGetAncestor(child2, GA_PARENT);
7647         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7648     }
7649     test = GetWindow(child2, GW_OWNER);
7650     ok(!test, "wrong owner %p\n", test);
7651
7652     test = SetParent(child2, parent);
7653     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
7654
7655     /* test owner/parent of the parent */
7656     test = GetParent(parent);
7657     ok(!test, "wrong parent %p\n", test);
7658     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
7659     if(pGetAncestor) {
7660         test = pGetAncestor(parent, GA_PARENT);
7661         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7662     }
7663     test = GetWindow(parent, GW_OWNER);
7664     ok(!test, "wrong owner %p\n", test);
7665
7666     /* test owner/parent of child1 */
7667     test = GetParent(child1);
7668     ok(test == parent, "wrong parent %p\n", test);
7669     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
7670     if(pGetAncestor) {
7671         test = pGetAncestor(child1, GA_PARENT);
7672         ok(test == parent, "wrong parent %p\n", test);
7673     }
7674     test = GetWindow(child1, GW_OWNER);
7675     ok(!test, "wrong owner %p\n", test);
7676
7677     /* test owner/parent of child2 */
7678     test = GetParent(child2);
7679     ok(test == parent, "wrong parent %p\n", test);
7680     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
7681     if(pGetAncestor) {
7682         test = pGetAncestor(child2, GA_PARENT);
7683         ok(test == parent, "wrong parent %p\n", test);
7684     }
7685     test = GetWindow(child2, GW_OWNER);
7686     ok(!test, "wrong owner %p\n", test);
7687
7688     /* test owner/parent of child3 */
7689     test = GetParent(child3);
7690     ok(test == child1, "wrong parent %p\n", test);
7691     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
7692     if(pGetAncestor) {
7693         test = pGetAncestor(child3, GA_PARENT);
7694         ok(test == child1, "wrong parent %p\n", test);
7695     }
7696     test = GetWindow(child3, GW_OWNER);
7697     ok(!test, "wrong owner %p\n", test);
7698
7699     /* test owner/parent of child4 */
7700     test = GetParent(child4);
7701     ok(test == parent, "wrong parent %p\n", test);
7702     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
7703     if(pGetAncestor) {
7704         test = pGetAncestor(child4, GA_PARENT);
7705         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
7706     }
7707     test = GetWindow(child4, GW_OWNER);
7708     ok(test == parent, "wrong owner %p\n", test);
7709
7710     flush_sequence();
7711
7712     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
7713            parent, child1, child2, child3, child4);
7714
7715     SetCapture(child4);
7716     test = GetCapture();
7717     ok(test == child4, "wrong capture window %p\n", test);
7718
7719     test_DestroyWindow_flag = TRUE;
7720     ret = DestroyWindow(parent);
7721     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7722     test_DestroyWindow_flag = FALSE;
7723     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
7724
7725     ok(!IsWindow(parent), "parent still exists\n");
7726     ok(!IsWindow(child1), "child1 still exists\n");
7727     ok(!IsWindow(child2), "child2 still exists\n");
7728     ok(!IsWindow(child3), "child3 still exists\n");
7729     ok(!IsWindow(child4), "child4 still exists\n");
7730
7731     test = GetCapture();
7732     ok(!test, "wrong capture window %p\n", test);
7733 }
7734
7735
7736 static const struct message WmDispatchPaint[] = {
7737     { WM_NCPAINT, sent },
7738     { WM_GETTEXT, sent|defwinproc|optional },
7739     { WM_GETTEXT, sent|defwinproc|optional },
7740     { WM_ERASEBKGND, sent },
7741     { 0 }
7742 };
7743
7744 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7745 {
7746     if (message == WM_PAINT) return 0;
7747     return MsgCheckProcA( hwnd, message, wParam, lParam );
7748 }
7749
7750 static void test_DispatchMessage(void)
7751 {
7752     RECT rect;
7753     MSG msg;
7754     int count;
7755     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7756                                100, 100, 200, 200, 0, 0, 0, NULL);
7757     ShowWindow( hwnd, SW_SHOW );
7758     UpdateWindow( hwnd );
7759     flush_events();
7760     flush_sequence();
7761     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
7762
7763     SetRect( &rect, -5, -5, 5, 5 );
7764     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7765     count = 0;
7766     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7767     {
7768         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7769         else
7770         {
7771             flush_sequence();
7772             DispatchMessage( &msg );
7773             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
7774             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7775             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
7776             if (++count > 10) break;
7777         }
7778     }
7779     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
7780
7781     trace("now without DispatchMessage\n");
7782     flush_sequence();
7783     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
7784     count = 0;
7785     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
7786     {
7787         if (msg.message != WM_PAINT) DispatchMessage( &msg );
7788         else
7789         {
7790             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7791             flush_sequence();
7792             /* this will send WM_NCCPAINT just like DispatchMessage does */
7793             GetUpdateRgn( hwnd, hrgn, TRUE );
7794             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
7795             DeleteObject( hrgn );
7796             GetClientRect( hwnd, &rect );
7797             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
7798             ok( !count, "Got multiple WM_PAINTs\n" );
7799             if (++count > 10) break;
7800         }
7801     }
7802     DestroyWindow(hwnd);
7803 }
7804
7805
7806 static const struct message WmUser[] = {
7807     { WM_USER, sent },
7808     { 0 }
7809 };
7810
7811 struct sendmsg_info
7812 {
7813     HWND  hwnd;
7814     DWORD timeout;
7815     DWORD ret;
7816 };
7817
7818 static DWORD CALLBACK send_msg_thread( LPVOID arg )
7819 {
7820     struct sendmsg_info *info = arg;
7821     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
7822     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
7823     return 0;
7824 }
7825
7826 static void wait_for_thread( HANDLE thread )
7827 {
7828     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
7829     {
7830         MSG msg;
7831         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
7832     }
7833 }
7834
7835 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7836 {
7837     if (message == WM_USER) Sleep(200);
7838     return MsgCheckProcA( hwnd, message, wParam, lParam );
7839 }
7840
7841 static void test_SendMessageTimeout(void)
7842 {
7843     HANDLE thread;
7844     struct sendmsg_info info;
7845     DWORD tid;
7846
7847     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
7848                                100, 100, 200, 200, 0, 0, 0, NULL);
7849     flush_events();
7850     flush_sequence();
7851
7852     info.timeout = 1000;
7853     info.ret = 0xdeadbeef;
7854     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7855     wait_for_thread( thread );
7856     CloseHandle( thread );
7857     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7858     ok_sequence( WmUser, "WmUser", FALSE );
7859
7860     info.timeout = 1;
7861     info.ret = 0xdeadbeef;
7862     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7863     Sleep(100);  /* SendMessageTimeout should timeout here */
7864     wait_for_thread( thread );
7865     CloseHandle( thread );
7866     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7867     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7868
7869     /* 0 means infinite timeout */
7870     info.timeout = 0;
7871     info.ret = 0xdeadbeef;
7872     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7873     Sleep(100);
7874     wait_for_thread( thread );
7875     CloseHandle( thread );
7876     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7877     ok_sequence( WmUser, "WmUser", FALSE );
7878
7879     /* timeout is treated as signed despite the prototype */
7880     info.timeout = 0x7fffffff;
7881     info.ret = 0xdeadbeef;
7882     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7883     Sleep(100);
7884     wait_for_thread( thread );
7885     CloseHandle( thread );
7886     ok( info.ret == 1, "SendMessageTimeout failed\n" );
7887     ok_sequence( WmUser, "WmUser", FALSE );
7888
7889     info.timeout = 0x80000000;
7890     info.ret = 0xdeadbeef;
7891     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7892     Sleep(100);
7893     wait_for_thread( thread );
7894     CloseHandle( thread );
7895     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
7896     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7897
7898     /* now check for timeout during message processing */
7899     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
7900     info.timeout = 100;
7901     info.ret = 0xdeadbeef;
7902     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
7903     wait_for_thread( thread );
7904     CloseHandle( thread );
7905     /* we should timeout but still get the message */
7906     ok( info.ret == 0, "SendMessageTimeout failed\n" );
7907     ok_sequence( WmUser, "WmUser", FALSE );
7908
7909     DestroyWindow( info.hwnd );
7910 }
7911
7912
7913 /****************** edit message test *************************/
7914 #define ID_EDIT 0x1234
7915 static const struct message sl_edit_setfocus[] =
7916 {
7917     { HCBT_SETFOCUS, hook },
7918     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7919     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7920     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7921     { WM_SETFOCUS, sent|wparam, 0 },
7922     { WM_CTLCOLOREDIT, sent|parent },
7923     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7924     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7925     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7926     { 0 }
7927 };
7928 static const struct message ml_edit_setfocus[] =
7929 {
7930     { HCBT_SETFOCUS, hook },
7931     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
7932     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7933     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7934     { WM_SETFOCUS, sent|wparam, 0 },
7935     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7936     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7937     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7938     { 0 }
7939 };
7940 static const struct message sl_edit_killfocus[] =
7941 {
7942     { HCBT_SETFOCUS, hook },
7943     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7944     { WM_KILLFOCUS, sent|wparam, 0 },
7945     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7946     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7947     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
7948     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
7949     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
7950     { 0 }
7951 };
7952 static const struct message sl_edit_lbutton_dblclk[] =
7953 {
7954     { WM_LBUTTONDBLCLK, sent },
7955     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7956     { 0 }
7957 };
7958 static const struct message sl_edit_lbutton_down[] =
7959 {
7960     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7961     { HCBT_SETFOCUS, hook },
7962     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7963     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7964     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7965     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7966     { WM_CTLCOLOREDIT, sent|parent },
7967     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7968     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7969     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7970     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7971     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7972     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7973     { WM_CTLCOLOREDIT, sent|parent|optional },
7974     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7975     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7976     { 0 }
7977 };
7978 static const struct message ml_edit_lbutton_down[] =
7979 {
7980     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
7981     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7982     { HCBT_SETFOCUS, hook },
7983     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
7984     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
7985     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
7986     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
7987     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7988     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7989     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
7990     { 0 }
7991 };
7992 static const struct message sl_edit_lbutton_up[] =
7993 {
7994     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
7995     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7996     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
7997     { WM_CAPTURECHANGED, sent|defwinproc },
7998     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
7999     { 0 }
8000 };
8001 static const struct message ml_edit_lbutton_up[] =
8002 {
8003     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8004     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8005     { WM_CAPTURECHANGED, sent|defwinproc },
8006     { 0 }
8007 };
8008
8009 static WNDPROC old_edit_proc;
8010
8011 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8012 {
8013     static long defwndproc_counter = 0;
8014     LRESULT ret;
8015     struct message msg;
8016
8017     trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
8018
8019     /* explicitly ignore WM_GETICON message */
8020     if (message == WM_GETICON) return 0;
8021
8022     msg.message = message;
8023     msg.flags = sent|wparam|lparam;
8024     if (defwndproc_counter) msg.flags |= defwinproc;
8025     msg.wParam = wParam;
8026     msg.lParam = lParam;
8027     add_message(&msg);
8028
8029     defwndproc_counter++;
8030     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8031     defwndproc_counter--;
8032
8033     return ret;
8034 }
8035
8036 static void subclass_edit(void)
8037 {
8038     WNDCLASSA cls;
8039
8040     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8041
8042     old_edit_proc = cls.lpfnWndProc;
8043
8044     cls.hInstance = GetModuleHandle(0);
8045     cls.lpfnWndProc = edit_hook_proc;
8046     cls.lpszClassName = "my_edit_class";
8047     UnregisterClass(cls.lpszClassName, cls.hInstance);
8048     if (!RegisterClassA(&cls)) assert(0);
8049 }
8050
8051 static void test_edit_messages(void)
8052 {
8053     HWND hwnd, parent;
8054     DWORD dlg_code;
8055
8056     subclass_edit();
8057     log_all_parent_messages++;
8058
8059     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8060                              100, 100, 200, 200, 0, 0, 0, NULL);
8061     ok (parent != 0, "Failed to create parent window\n");
8062
8063     /* test single line edit */
8064     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8065                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8066     ok(hwnd != 0, "Failed to create edit window\n");
8067
8068     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8069     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8070
8071     ShowWindow(hwnd, SW_SHOW);
8072     UpdateWindow(hwnd);
8073     SetFocus(0);
8074     flush_sequence();
8075
8076     SetFocus(hwnd);
8077     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8078
8079     SetFocus(0);
8080     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8081
8082     SetFocus(0);
8083     ReleaseCapture();
8084     flush_sequence();
8085
8086     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8087     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8088
8089     SetFocus(0);
8090     ReleaseCapture();
8091     flush_sequence();
8092
8093     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8094     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8095
8096     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8097     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8098
8099     DestroyWindow(hwnd);
8100
8101     /* test multiline edit */
8102     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8103                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8104     ok(hwnd != 0, "Failed to create edit window\n");
8105
8106     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8107     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8108        "wrong dlg_code %08x\n", dlg_code);
8109
8110     ShowWindow(hwnd, SW_SHOW);
8111     UpdateWindow(hwnd);
8112     SetFocus(0);
8113     flush_sequence();
8114
8115     SetFocus(hwnd);
8116     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8117
8118     SetFocus(0);
8119     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8120
8121     SetFocus(0);
8122     ReleaseCapture();
8123     flush_sequence();
8124
8125     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8126     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8127
8128     SetFocus(0);
8129     ReleaseCapture();
8130     flush_sequence();
8131
8132     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8133     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8134
8135     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8136     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8137
8138     DestroyWindow(hwnd);
8139     DestroyWindow(parent);
8140
8141     log_all_parent_messages--;
8142 }
8143
8144 /**************************** End of Edit test ******************************/
8145
8146 static const struct message WmKeyDownSkippedSeq[] =
8147 {
8148     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8149     { 0 }
8150 };
8151 static const struct message WmKeyUpSkippedSeq[] =
8152 {
8153     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8154     { 0 }
8155 };
8156
8157 #define EV_START_STOP 0
8158 #define EV_SENDMSG 1
8159 #define EV_ACK 2
8160
8161 struct peekmsg_info
8162 {
8163     HWND  hwnd;
8164     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8165 };
8166
8167 static DWORD CALLBACK send_msg_thread_2(void *param)
8168 {
8169     DWORD ret;
8170     struct peekmsg_info *info = param;
8171
8172     trace("thread: waiting for start\n");
8173     WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
8174     trace("thread: looping\n");
8175
8176     while (1)
8177     {
8178         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8179
8180         switch (ret)
8181         {
8182         case WAIT_OBJECT_0 + EV_START_STOP:
8183             trace("thread: exiting\n");
8184             return 0;
8185
8186         case WAIT_OBJECT_0 + EV_SENDMSG:
8187             trace("thread: sending message\n");
8188             SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
8189             SetEvent(info->hevent[EV_ACK]);
8190             break;
8191
8192         default:
8193             trace("unexpected return: %04x\n", ret);
8194             assert(0);
8195             break;
8196         }
8197     }
8198     return 0;
8199 }
8200
8201 static void test_PeekMessage(void)
8202 {
8203     MSG msg;
8204     HANDLE hthread;
8205     DWORD tid, qstatus;
8206     UINT qs_all_input = QS_ALLINPUT;
8207     UINT qs_input = QS_INPUT;
8208     BOOL ret;
8209     struct peekmsg_info info;
8210
8211     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8212                               100, 100, 200, 200, 0, 0, 0, NULL);
8213     assert(info.hwnd);
8214     ShowWindow(info.hwnd, SW_SHOW);
8215     UpdateWindow(info.hwnd);
8216     SetFocus(info.hwnd);
8217
8218     info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
8219     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8220     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8221
8222     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8223     Sleep(100);
8224
8225     trace("signalling to start looping\n");
8226     SetEvent(info.hevent[EV_START_STOP]);
8227
8228     flush_events();
8229     flush_sequence();
8230
8231     SetLastError(0xdeadbeef);
8232     qstatus = GetQueueStatus(qs_all_input);
8233     if (GetLastError() == ERROR_INVALID_FLAGS)
8234     {
8235         trace("QS_RAWINPUT not supported on this platform\n");
8236         qs_all_input &= ~QS_RAWINPUT;
8237         qs_input &= ~QS_RAWINPUT;
8238     }
8239     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8240
8241     trace("signalling to send message\n");
8242     SetEvent(info.hevent[EV_SENDMSG]);
8243     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8244
8245     /* pass invalid QS_xxxx flags */
8246     SetLastError(0xdeadbeef);
8247     qstatus = GetQueueStatus(0xffffffff);
8248     ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
8249     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8250
8251     qstatus = GetQueueStatus(qs_all_input);
8252     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8253        "wrong qstatus %08x\n", qstatus);
8254
8255     msg.message = 0;
8256     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8257     ok(!ret,
8258        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8259         msg.message);
8260     ok_sequence(WmUser, "WmUser", FALSE);
8261
8262     qstatus = GetQueueStatus(qs_all_input);
8263     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8264
8265     keybd_event('N', 0, 0, 0);
8266     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8267     qstatus = GetQueueStatus(qs_all_input);
8268     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8269        "wrong qstatus %08x\n", qstatus);
8270
8271     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8272     qstatus = GetQueueStatus(qs_all_input);
8273     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8274        "wrong qstatus %08x\n", qstatus);
8275
8276     InvalidateRect(info.hwnd, NULL, FALSE);
8277     qstatus = GetQueueStatus(qs_all_input);
8278     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8279        "wrong qstatus %08x\n", qstatus);
8280
8281     trace("signalling to send message\n");
8282     SetEvent(info.hevent[EV_SENDMSG]);
8283     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8284
8285     qstatus = GetQueueStatus(qs_all_input);
8286     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8287        "wrong qstatus %08x\n", qstatus);
8288
8289     msg.message = 0;
8290     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8291     ok(!ret,
8292        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8293         msg.message);
8294     ok_sequence(WmUser, "WmUser", FALSE);
8295
8296     qstatus = GetQueueStatus(qs_all_input);
8297     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8298        "wrong qstatus %08x\n", qstatus);
8299
8300     trace("signalling to send message\n");
8301     SetEvent(info.hevent[EV_SENDMSG]);
8302     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8303
8304     qstatus = GetQueueStatus(qs_all_input);
8305     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8306        "wrong qstatus %08x\n", qstatus);
8307
8308     msg.message = 0;
8309     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8310     ok(!ret,
8311        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8312         msg.message);
8313     ok_sequence(WmUser, "WmUser", FALSE);
8314
8315     qstatus = GetQueueStatus(qs_all_input);
8316     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8317        "wrong qstatus %08x\n", qstatus);
8318
8319     msg.message = 0;
8320     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8321     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8322        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8323        ret, msg.message, msg.wParam);
8324     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8325
8326     qstatus = GetQueueStatus(qs_all_input);
8327     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8328        "wrong qstatus %08x\n", qstatus);
8329
8330     msg.message = 0;
8331     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8332     ok(!ret,
8333        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8334         msg.message);
8335     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8336
8337     qstatus = GetQueueStatus(qs_all_input);
8338     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
8339        "wrong qstatus %08x\n", qstatus);
8340
8341     msg.message = 0;
8342     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8343     ok(ret && msg.message == WM_PAINT,
8344        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
8345     DispatchMessageA(&msg);
8346     ok_sequence(WmPaint, "WmPaint", FALSE);
8347
8348     qstatus = GetQueueStatus(qs_all_input);
8349     ok(qstatus == MAKELONG(0, QS_KEY),
8350        "wrong qstatus %08x\n", qstatus);
8351
8352     msg.message = 0;
8353     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
8354     ok(!ret,
8355        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8356         msg.message);
8357     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8358
8359     qstatus = GetQueueStatus(qs_all_input);
8360     ok(qstatus == MAKELONG(0, QS_KEY),
8361        "wrong qstatus %08x\n", qstatus);
8362
8363     trace("signalling to send message\n");
8364     SetEvent(info.hevent[EV_SENDMSG]);
8365     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8366
8367     qstatus = GetQueueStatus(qs_all_input);
8368     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
8369        "wrong qstatus %08x\n", qstatus);
8370
8371     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8372
8373     qstatus = GetQueueStatus(qs_all_input);
8374     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8375        "wrong qstatus %08x\n", qstatus);
8376
8377     msg.message = 0;
8378     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8379     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8380        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8381        ret, msg.message, msg.wParam);
8382     ok_sequence(WmUser, "WmUser", FALSE);
8383
8384     qstatus = GetQueueStatus(qs_all_input);
8385     ok(qstatus == MAKELONG(0, QS_KEY),
8386        "wrong qstatus %08x\n", qstatus);
8387
8388     msg.message = 0;
8389     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
8390     ok(!ret,
8391        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8392         msg.message);
8393     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8394
8395     qstatus = GetQueueStatus(qs_all_input);
8396     ok(qstatus == MAKELONG(0, QS_KEY),
8397        "wrong qstatus %08x\n", qstatus);
8398
8399     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8400
8401     qstatus = GetQueueStatus(qs_all_input);
8402     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8403        "wrong qstatus %08x\n", qstatus);
8404
8405     trace("signalling to send message\n");
8406     SetEvent(info.hevent[EV_SENDMSG]);
8407     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8408
8409     qstatus = GetQueueStatus(qs_all_input);
8410     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
8411        "wrong qstatus %08x\n", qstatus);
8412
8413     msg.message = 0;
8414     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
8415     ok(!ret,
8416        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8417         msg.message);
8418     ok_sequence(WmUser, "WmUser", FALSE);
8419
8420     qstatus = GetQueueStatus(qs_all_input);
8421     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8422        "wrong qstatus %08x\n", qstatus);
8423
8424     msg.message = 0;
8425     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8426         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8427     else /* workaround for a missing QS_RAWINPUT support */
8428         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
8429     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
8430        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
8431        ret, msg.message, msg.wParam);
8432     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
8433
8434     qstatus = GetQueueStatus(qs_all_input);
8435     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
8436        "wrong qstatus %08x\n", qstatus);
8437
8438     msg.message = 0;
8439     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
8440         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
8441     else /* workaround for a missing QS_RAWINPUT support */
8442         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
8443     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
8444        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
8445        ret, msg.message, msg.wParam);
8446     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
8447
8448     qstatus = GetQueueStatus(qs_all_input);
8449     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8450        "wrong qstatus %08x\n", qstatus);
8451
8452     msg.message = 0;
8453     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
8454     ok(!ret,
8455        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8456         msg.message);
8457     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8458
8459     qstatus = GetQueueStatus(qs_all_input);
8460     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8461        "wrong qstatus %08x\n", qstatus);
8462
8463     msg.message = 0;
8464     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8465     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
8466        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
8467        ret, msg.message, msg.wParam);
8468     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8469
8470     qstatus = GetQueueStatus(qs_all_input);
8471     ok(qstatus == 0,
8472        "wrong qstatus %08x\n", qstatus);
8473
8474     msg.message = 0;
8475     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8476     ok(!ret,
8477        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8478         msg.message);
8479     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8480
8481     qstatus = GetQueueStatus(qs_all_input);
8482     ok(qstatus == 0,
8483        "wrong qstatus %08x\n", qstatus);
8484
8485     /* test whether presence of the quit flag in the queue affects
8486      * the queue state
8487      */
8488     PostQuitMessage(0x1234abcd);
8489
8490     qstatus = GetQueueStatus(qs_all_input);
8491     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8492        "wrong qstatus %08x\n", qstatus);
8493
8494     PostMessageA(info.hwnd, WM_USER, 0, 0);
8495
8496     qstatus = GetQueueStatus(qs_all_input);
8497     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
8498        "wrong qstatus %08x\n", qstatus);
8499
8500     msg.message = 0;
8501     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8502     ok(ret && msg.message == WM_USER,
8503        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
8504     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8505
8506     qstatus = GetQueueStatus(qs_all_input);
8507     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8508        "wrong qstatus %08x\n", qstatus);
8509
8510     msg.message = 0;
8511     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8512     ok(ret && msg.message == WM_QUIT,
8513        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
8514     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
8515     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
8516     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8517
8518     qstatus = GetQueueStatus(qs_all_input);
8519 todo_wine {
8520     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
8521        "wrong qstatus %08x\n", qstatus);
8522 }
8523
8524     msg.message = 0;
8525     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8526     ok(!ret,
8527        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8528         msg.message);
8529     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
8530
8531     qstatus = GetQueueStatus(qs_all_input);
8532     ok(qstatus == 0,
8533        "wrong qstatus %08x\n", qstatus);
8534
8535     trace("signalling to exit\n");
8536     SetEvent(info.hevent[EV_START_STOP]);
8537
8538     WaitForSingleObject(hthread, INFINITE);
8539
8540     CloseHandle(hthread);
8541     CloseHandle(info.hevent[0]);
8542     CloseHandle(info.hevent[1]);
8543     CloseHandle(info.hevent[2]);
8544
8545     DestroyWindow(info.hwnd);
8546 }
8547
8548 static void wait_move_event(HWND hwnd, int x, int y)
8549 {
8550     MSG msg;
8551     DWORD time;
8552     BOOL  ret;
8553     int go = 0;
8554
8555     time = GetTickCount();
8556     while (GetTickCount() - time < 200 && !go) {
8557         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8558         go  = ret && msg.pt.x > x && msg.pt.y > y;
8559     }
8560 }
8561
8562 #define STEP 20
8563 static void test_PeekMessage2(void)
8564 {
8565     HWND hwnd;
8566     BOOL ret;
8567     MSG msg;
8568     UINT message;
8569     DWORD time1, time2, time3;
8570     int x1, y1, x2, y2, x3, y3;
8571     POINT pos;
8572
8573     time1 = time2 = time3 = 0;
8574     x1 = y1 = x2 = y2 = x3 = y3 = 0;
8575
8576     /* Initialise window and make sure it is ready for events */
8577     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
8578                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
8579     assert(hwnd);
8580     trace("Window for test_PeekMessage2 %p\n", hwnd);
8581     ShowWindow(hwnd, SW_SHOW);
8582     UpdateWindow(hwnd);
8583     SetFocus(hwnd);
8584     GetCursorPos(&pos);
8585     SetCursorPos(100, 100);
8586     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
8587     flush_events();
8588
8589     /* Do initial mousemove, wait until we can see it
8590        and then do our test peek with PM_NOREMOVE. */
8591     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8592     wait_move_event(hwnd, 80, 80);
8593
8594     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8595     ok(ret, "no message available\n");
8596     if (ret) {
8597         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8598         message = msg.message;
8599         time1 = msg.time;
8600         x1 = msg.pt.x;
8601         y1 = msg.pt.y;
8602         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8603     }
8604
8605     /* Allow time to advance a bit, and then simulate the user moving their
8606      * mouse around. After that we peek again with PM_NOREMOVE.
8607      * Although the previous mousemove message was never removed, the
8608      * mousemove we now peek should reflect the recent mouse movements
8609      * because the input queue will merge the move events. */
8610     Sleep(2);
8611     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8612     wait_move_event(hwnd, x1, y1);
8613
8614     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8615     ok(ret, "no message available\n");
8616     if (ret) {
8617         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8618         message = msg.message;
8619         time2 = msg.time;
8620         x2 = msg.pt.x;
8621         y2 = msg.pt.y;
8622         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8623         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
8624         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
8625     }
8626
8627     /* Have another go, to drive the point home */
8628     Sleep(2);
8629     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
8630     wait_move_event(hwnd, x2, y2);
8631
8632     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
8633     ok(ret, "no message available\n");
8634     if (ret) {
8635         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
8636         message = msg.message;
8637         time3 = msg.time;
8638         x3 = msg.pt.x;
8639         y3 = msg.pt.y;
8640         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
8641         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
8642         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
8643     }
8644
8645     DestroyWindow(hwnd);
8646     SetCursorPos(pos.x, pos.y);
8647     flush_events();
8648 }
8649
8650 static void test_quit_message(void)
8651 {
8652     MSG msg;
8653     BOOL ret;
8654
8655     /* test using PostQuitMessage */
8656     PostQuitMessage(0xbeef);
8657
8658     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8659     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8660     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8661     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8662
8663     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8664     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8665
8666     ret = GetMessage(&msg, NULL, 0, 0);
8667     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8668     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8669
8670     /* note: WM_QUIT message received after WM_USER message */
8671     ret = GetMessage(&msg, NULL, 0, 0);
8672     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8673     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8674     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
8675
8676     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
8677     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
8678
8679     /* now test with PostThreadMessage - different behaviour! */
8680     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
8681
8682     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
8683     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
8684     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8685     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
8686
8687     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
8688     ok(ret, "PostMessage failed with error %d\n", GetLastError());
8689
8690     /* note: we receive the WM_QUIT message first this time */
8691     ret = GetMessage(&msg, NULL, 0, 0);
8692     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
8693     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
8694     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
8695
8696     ret = GetMessage(&msg, NULL, 0, 0);
8697     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
8698     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
8699 }
8700
8701 static const struct message WmMouseHoverSeq[] = {
8702     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
8703     { WM_MOUSEACTIVATE, sent|optional },
8704     { WM_TIMER, sent|optional }, /* XP sends it */
8705     { WM_SYSTIMER, sent },
8706     { WM_MOUSEHOVER, sent|wparam, 0 },
8707     { 0 }
8708 };
8709
8710 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
8711 {
8712     MSG msg;
8713     DWORD start_ticks, end_ticks;
8714
8715     start_ticks = GetTickCount();
8716     /* add some deviation (5%) to cover not expected delays */
8717     start_ticks += timeout / 20;
8718
8719     do
8720     {
8721         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
8722         {
8723             /* Timer proc messages are not dispatched to the window proc,
8724              * and therefore not logged.
8725              */
8726             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
8727             {
8728                 struct message s_msg;
8729
8730                 s_msg.message = msg.message;
8731                 s_msg.flags = sent|wparam|lparam;
8732                 s_msg.wParam = msg.wParam;
8733                 s_msg.lParam = msg.lParam;
8734                 add_message(&s_msg);
8735             }
8736             DispatchMessage(&msg);
8737         }
8738
8739         end_ticks = GetTickCount();
8740
8741         /* inject WM_MOUSEMOVE to see how it changes tracking */
8742         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
8743         {
8744             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8745             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8746
8747             inject_mouse_move = FALSE;
8748         }
8749     } while (start_ticks + timeout >= end_ticks);
8750 }
8751
8752 static void test_TrackMouseEvent(void)
8753 {
8754     TRACKMOUSEEVENT tme;
8755     BOOL ret;
8756     HWND hwnd, hchild;
8757     RECT rc_parent, rc_child;
8758     UINT default_hover_time, hover_width = 0, hover_height = 0;
8759
8760 #define track_hover(track_hwnd, track_hover_time) \
8761     tme.cbSize = sizeof(tme); \
8762     tme.dwFlags = TME_HOVER; \
8763     tme.hwndTrack = track_hwnd; \
8764     tme.dwHoverTime = track_hover_time; \
8765     SetLastError(0xdeadbeef); \
8766     ret = pTrackMouseEvent(&tme); \
8767     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
8768
8769 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
8770     tme.cbSize = sizeof(tme); \
8771     tme.dwFlags = TME_QUERY; \
8772     tme.hwndTrack = (HWND)0xdeadbeef; \
8773     tme.dwHoverTime = 0xdeadbeef; \
8774     SetLastError(0xdeadbeef); \
8775     ret = pTrackMouseEvent(&tme); \
8776     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
8777     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
8778     ok(tme.dwFlags == (expected_track_flags), \
8779        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
8780     ok(tme.hwndTrack == (expected_track_hwnd), \
8781        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
8782     ok(tme.dwHoverTime == (expected_hover_time), \
8783        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
8784
8785 #define track_hover_cancel(track_hwnd) \
8786     tme.cbSize = sizeof(tme); \
8787     tme.dwFlags = TME_HOVER | TME_CANCEL; \
8788     tme.hwndTrack = track_hwnd; \
8789     tme.dwHoverTime = 0xdeadbeef; \
8790     SetLastError(0xdeadbeef); \
8791     ret = pTrackMouseEvent(&tme); \
8792     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
8793
8794     default_hover_time = 0xdeadbeef;
8795     SetLastError(0xdeadbeef);
8796     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
8797     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
8798     if (!ret) default_hover_time = 400;
8799     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
8800
8801     SetLastError(0xdeadbeef);
8802     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
8803     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
8804     if (!ret) hover_width = 4;
8805     SetLastError(0xdeadbeef);
8806     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
8807     ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
8808     if (!ret) hover_height = 4;
8809     trace("hover rect is %u x %d\n", hover_width, hover_height);
8810
8811     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
8812                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8813                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8814                           NULL, NULL, 0);
8815     assert(hwnd);
8816
8817     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
8818                           WS_CHILD | WS_BORDER | WS_VISIBLE,
8819                           50, 50, 200, 200, hwnd,
8820                           NULL, NULL, 0);
8821     assert(hchild);
8822
8823     flush_events();
8824     flush_sequence();
8825
8826     tme.cbSize = 0;
8827     tme.dwFlags = TME_QUERY;
8828     tme.hwndTrack = (HWND)0xdeadbeef;
8829     tme.dwHoverTime = 0xdeadbeef;
8830     SetLastError(0xdeadbeef);
8831     ret = pTrackMouseEvent(&tme);
8832     ok(!ret, "TrackMouseEvent should fail\n");
8833     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
8834
8835     tme.cbSize = sizeof(tme);
8836     tme.dwFlags = TME_HOVER;
8837     tme.hwndTrack = (HWND)0xdeadbeef;
8838     tme.dwHoverTime = 0xdeadbeef;
8839     SetLastError(0xdeadbeef);
8840     ret = pTrackMouseEvent(&tme);
8841     ok(!ret, "TrackMouseEvent should fail\n");
8842     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8843
8844     tme.cbSize = sizeof(tme);
8845     tme.dwFlags = TME_HOVER | TME_CANCEL;
8846     tme.hwndTrack = (HWND)0xdeadbeef;
8847     tme.dwHoverTime = 0xdeadbeef;
8848     SetLastError(0xdeadbeef);
8849     ret = pTrackMouseEvent(&tme);
8850     ok(!ret, "TrackMouseEvent should fail\n");
8851     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
8852
8853     GetWindowRect(hwnd, &rc_parent);
8854     GetWindowRect(hchild, &rc_child);
8855     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
8856
8857     /* Process messages so that the system updates its internal current
8858      * window and hittest, otherwise TrackMouseEvent calls don't have any
8859      * effect.
8860      */
8861     flush_events();
8862     flush_sequence();
8863
8864     track_query(0, NULL, 0);
8865     track_hover(hchild, 0);
8866     track_query(0, NULL, 0);
8867
8868     flush_events();
8869     flush_sequence();
8870
8871     track_hover(hwnd, 0);
8872     track_query(TME_HOVER, hwnd, default_hover_time);
8873
8874     pump_msg_loop_timeout(default_hover_time, FALSE);
8875     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8876
8877     track_query(0, NULL, 0);
8878
8879     track_hover(hwnd, HOVER_DEFAULT);
8880     track_query(TME_HOVER, hwnd, default_hover_time);
8881
8882     Sleep(default_hover_time / 2);
8883     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8884     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8885
8886     track_query(TME_HOVER, hwnd, default_hover_time);
8887
8888     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
8889     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8890
8891     track_query(0, NULL, 0);
8892
8893     track_hover(hwnd, HOVER_DEFAULT);
8894     track_query(TME_HOVER, hwnd, default_hover_time);
8895
8896     pump_msg_loop_timeout(default_hover_time, TRUE);
8897     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
8898
8899     track_query(0, NULL, 0);
8900
8901     track_hover(hwnd, HOVER_DEFAULT);
8902     track_query(TME_HOVER, hwnd, default_hover_time);
8903     track_hover_cancel(hwnd);
8904
8905     DestroyWindow(hwnd);
8906
8907 #undef track_hover
8908 #undef track_query
8909 #undef track_hover_cancel
8910 }
8911
8912
8913 static const struct message WmSetWindowRgn[] = {
8914     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8915     { WM_NCCALCSIZE, sent|wparam, 1 },
8916     { WM_NCPAINT, sent }, /* wparam != 1 */
8917     { WM_GETTEXT, sent|defwinproc|optional },
8918     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8919     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8920     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8921     { 0 }
8922 };
8923
8924 static const struct message WmSetWindowRgn_no_redraw[] = {
8925     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8926     { WM_NCCALCSIZE, sent|wparam, 1 },
8927     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
8928     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8929     { 0 }
8930 };
8931
8932 static const struct message WmSetWindowRgn_clear[] = {
8933     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, /* some versions of 2000/XP also has SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE in wparam */
8934     { WM_NCCALCSIZE, sent|wparam, 1 },
8935     { WM_NCPAINT, sent }, /* wparam != 1 */
8936     { WM_GETTEXT, sent|defwinproc|optional },
8937     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
8938     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
8939     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
8940     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
8941     { WM_GETTEXT, sent|defwinproc|optional },
8942     { WM_ERASEBKGND, sent|optional },
8943     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8944     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
8945     { 0 }
8946 };
8947
8948 static void test_SetWindowRgn(void)
8949 {
8950     HRGN hrgn;
8951     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
8952                                 100, 100, 200, 200, 0, 0, 0, NULL);
8953     ok( hwnd != 0, "Failed to create overlapped window\n" );
8954
8955     ShowWindow( hwnd, SW_SHOW );
8956     UpdateWindow( hwnd );
8957     flush_events();
8958     flush_sequence();
8959
8960     trace("testing SetWindowRgn\n");
8961     hrgn = CreateRectRgn( 0, 0, 150, 150 );
8962     SetWindowRgn( hwnd, hrgn, TRUE );
8963     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
8964
8965     hrgn = CreateRectRgn( 30, 30, 160, 160 );
8966     SetWindowRgn( hwnd, hrgn, FALSE );
8967     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
8968
8969     hrgn = CreateRectRgn( 0, 0, 180, 180 );
8970     SetWindowRgn( hwnd, hrgn, TRUE );
8971     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
8972
8973     SetWindowRgn( hwnd, 0, TRUE );
8974     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
8975
8976     DestroyWindow( hwnd );
8977 }
8978
8979 /*************************** ShowWindow() test ******************************/
8980 static const struct message WmShowNormal[] = {
8981     { WM_SHOWWINDOW, sent|wparam, 1 },
8982     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8983     { HCBT_ACTIVATE, hook },
8984     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
8985     { HCBT_SETFOCUS, hook },
8986     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8987     { 0 }
8988 };
8989 static const struct message WmShow[] = {
8990     { WM_SHOWWINDOW, sent|wparam, 1 },
8991     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
8992     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
8993     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
8994     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
8995     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
8996     { 0 }
8997 };
8998 static const struct message WmShowNoActivate_1[] = {
8999     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9000     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
9001     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000 },
9002     { WM_MOVE, sent|defwinproc },
9003     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9004     { 0 }
9005 };
9006 static const struct message WmShowNoActivate_2[] = {
9007     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9008     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9009     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9010     { WM_MOVE, sent|defwinproc },
9011     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9012     { HCBT_SETFOCUS, hook },
9013     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9014     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9015     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9016     { 0 }
9017 };
9018 static const struct message WmShowNA_1[] = {
9019     { WM_SHOWWINDOW, sent|wparam, 1 },
9020     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9021     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9022     { 0 }
9023 };
9024 static const struct message WmShowNA_2[] = {
9025     { WM_SHOWWINDOW, sent|wparam, 1 },
9026     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9027     { 0 }
9028 };
9029 static const struct message WmRestore_1[] = {
9030     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9031     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9032     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9033     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9034     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9035     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9036     { WM_MOVE, sent|defwinproc },
9037     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9038     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9039     { 0 }
9040 };
9041 static const struct message WmRestore_2[] = {
9042     { WM_SHOWWINDOW, sent|wparam, 1 },
9043     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9044     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9045     { 0 }
9046 };
9047 static const struct message WmRestore_3[] = {
9048     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9049     { WM_GETMINMAXINFO, sent },
9050     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9051     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9052     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9053     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9054     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9055     { WM_MOVE, sent|defwinproc },
9056     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9057     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9058     { 0 }
9059 };
9060 static const struct message WmRestore_4[] = {
9061     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9062     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9063     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9064     { WM_MOVE, sent|defwinproc },
9065     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9066     { 0 }
9067 };
9068 static const struct message WmRestore_5[] = {
9069     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9070     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9071     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9072     { WM_MOVE, sent|defwinproc },
9073     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9074     { 0 }
9075 };
9076 static const struct message WmHide_1[] = {
9077     { WM_SHOWWINDOW, sent|wparam, 0 },
9078     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9079     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9080     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9081     { 0 }
9082 };
9083 static const struct message WmHide_2[] = {
9084     { WM_SHOWWINDOW, sent|wparam, 0 },
9085     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9086     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9087     { 0 }
9088 };
9089 static const struct message WmHide_3[] = {
9090     { WM_SHOWWINDOW, sent|wparam, 0 },
9091     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9092     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9093     { HCBT_SETFOCUS, hook },
9094     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9095     { 0 }
9096 };
9097 static const struct message WmShowMinimized_1[] = {
9098     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9099     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9100     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9101     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9102     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9103     { WM_MOVE, sent|defwinproc },
9104     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9105     { 0 }
9106 };
9107 static const struct message WmMinimize_1[] = {
9108     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9109     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9110     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9111     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9112     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9113     { WM_MOVE, sent|defwinproc },
9114     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9115     { 0 }
9116 };
9117 static const struct message WmMinimize_2[] = {
9118     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9119     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9120     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9121     { WM_MOVE, sent|defwinproc },
9122     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9123     { 0 }
9124 };
9125 static const struct message WmMinimize_3[] = {
9126     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9127     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9128     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9129     { WM_MOVE, sent|defwinproc },
9130     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9131     { 0 }
9132 };
9133 static const struct message WmShowMinNoActivate[] = {
9134     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9135     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9136     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9137     { 0 }
9138 };
9139 static const struct message WmMinMax_1[] = {
9140     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9141     { 0 }
9142 };
9143 static const struct message WmMinMax_2[] = {
9144     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9145     { 0 }
9146 };
9147 static const struct message WmMinMax_3[] = {
9148     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9149     { 0 }
9150 };
9151 static const struct message WmMinMax_4[] = {
9152     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9153     { 0 }
9154 };
9155 static const struct message WmShowMaximized_1[] = {
9156     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9157     { WM_GETMINMAXINFO, sent },
9158     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9159     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9160     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9161     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9162     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9163     { WM_MOVE, sent|defwinproc },
9164     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9165     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9166     { 0 }
9167 };
9168 static const struct message WmShowMaximized_2[] = {
9169     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9170     { WM_GETMINMAXINFO, sent },
9171     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
9172     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9173     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
9174     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
9175     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9176     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|0x8000 },
9177     { WM_MOVE, sent|defwinproc },
9178     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9179     { HCBT_SETFOCUS, hook },
9180     { 0 }
9181 };
9182 static const struct message WmShowMaximized_3[] = {
9183     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9184     { WM_GETMINMAXINFO, sent },
9185     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9186     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|0x8000 },
9187     { WM_MOVE, sent|defwinproc },
9188     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9189     { 0 }
9190 };
9191
9192 static void test_ShowWindow(void)
9193 {
9194     /* ShowWindow commands in random order */
9195     static const struct
9196     {
9197         INT cmd; /* ShowWindow command */
9198         LPARAM ret; /* ShowWindow return value */
9199         DWORD style; /* window style after the command */
9200         const struct message *msg; /* message sequence the command produces */
9201         BOOL todo_msg; /* message sequence doesn't match what Wine does */
9202     } sw[] =
9203     {
9204 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
9205 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9206 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9207 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9208 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
9209 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
9210 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
9211 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9212 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
9213 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9214 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
9215 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
9216 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
9217 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9218 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
9219 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9220 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
9221 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9222 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
9223 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9224 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9225 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
9226 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
9227 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9228 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9229 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
9230 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
9231 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9232 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
9233 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
9234 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9235 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
9236 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9237 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE }, /* what does this mean?! */
9238 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, TRUE },
9239 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9240 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
9241 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9242 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9243 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, TRUE },
9244 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9245 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
9246 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
9247 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, TRUE },
9248 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
9249 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
9250 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
9251 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
9252 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
9253 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
9254 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
9255 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
9256 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
9257 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, TRUE },
9258 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
9259 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
9260 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
9261     };
9262     HWND hwnd;
9263     DWORD style;
9264     LPARAM ret;
9265     INT i;
9266
9267 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
9268     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
9269                           120, 120, 90, 90,
9270                           0, 0, 0, NULL);
9271     assert(hwnd);
9272
9273     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9274     ok(style == 0, "expected style 0, got %08x\n", style);
9275
9276     flush_events();
9277     flush_sequence();
9278
9279     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
9280     {
9281         static const char * const sw_cmd_name[13] =
9282         {
9283             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
9284             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
9285             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
9286             "SW_NORMALNA" /* 0xCC */
9287         };
9288         char comment[64];
9289         INT idx; /* index into the above array of names */
9290
9291         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
9292
9293         style = GetWindowLong(hwnd, GWL_STYLE);
9294         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
9295         ret = ShowWindow(hwnd, sw[i].cmd);
9296         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
9297         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
9298         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
9299
9300         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
9301         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
9302
9303         flush_events();
9304         flush_sequence();
9305     }
9306
9307     DestroyWindow(hwnd);
9308 }
9309
9310 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9311 {
9312     struct message msg;
9313
9314     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
9315
9316     switch (message)
9317     {
9318     case WM_WINDOWPOSCHANGING:
9319     case WM_WINDOWPOSCHANGED:
9320     {
9321         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
9322
9323         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
9324         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
9325               winpos->hwnd, winpos->hwndInsertAfter,
9326               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
9327         dump_winpos_flags(winpos->flags);
9328
9329         /* Log only documented flags, win2k uses 0x1000 and 0x2000
9330          * in the high word for internal purposes
9331          */
9332         wParam = winpos->flags & 0xffff;
9333         /* We are not interested in the flags that don't match under XP and Win9x */
9334         wParam &= ~(SWP_NOZORDER);
9335         break;
9336     }
9337
9338     /* explicitly ignore WM_GETICON message */
9339     case WM_GETICON:
9340         return 0;
9341     }
9342
9343     msg.message = message;
9344     msg.flags = sent|wparam|lparam;
9345     msg.wParam = wParam;
9346     msg.lParam = lParam;
9347     add_message(&msg);
9348
9349     /* calling DefDlgProc leads to a recursion under XP */
9350
9351     switch (message)
9352     {
9353     case WM_INITDIALOG:
9354     case WM_GETDLGCODE:
9355         return 0;
9356     }
9357     return 1;
9358 }
9359
9360 static const struct message WmDefDlgSetFocus_1[] = {
9361     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9362     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9363     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9364     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9365     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9366     { HCBT_SETFOCUS, hook },
9367     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9368     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9369     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9370     { WM_SETFOCUS, sent|wparam, 0 },
9371     { WM_CTLCOLOREDIT, sent },
9372     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9373     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9374     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9375     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
9376     { 0 }
9377 };
9378 static const struct message WmDefDlgSetFocus_2[] = {
9379     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
9380     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
9381     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
9382     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
9383     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
9384     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9385     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
9386     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9387     { 0 }
9388 };
9389 /* Creation of a dialog */
9390 static const struct message WmCreateDialogParamSeq_1[] = {
9391     { HCBT_CREATEWND, hook },
9392     { WM_NCCREATE, sent },
9393     { WM_NCCALCSIZE, sent|wparam, 0 },
9394     { WM_CREATE, sent },
9395     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9396     { WM_SIZE, sent|wparam, SIZE_RESTORED },
9397     { WM_MOVE, sent },
9398     { WM_SETFONT, sent },
9399     { WM_INITDIALOG, sent },
9400     { WM_CHANGEUISTATE, sent|optional },
9401     { 0 }
9402 };
9403 /* Creation of a dialog */
9404 static const struct message WmCreateDialogParamSeq_2[] = {
9405     { HCBT_CREATEWND, hook },
9406     { WM_NCCREATE, sent },
9407     { WM_NCCALCSIZE, sent|wparam, 0 },
9408     { WM_CREATE, sent },
9409     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
9410     { WM_SIZE, sent|wparam, SIZE_RESTORED },
9411     { WM_MOVE, sent },
9412     { WM_CHANGEUISTATE, sent|optional },
9413     { 0 }
9414 };
9415
9416 static void test_dialog_messages(void)
9417 {
9418     WNDCLASS cls;
9419     HWND hdlg, hedit1, hedit2, hfocus;
9420     LRESULT ret;
9421
9422 #define set_selection(hctl, start, end) \
9423     ret = SendMessage(hctl, EM_SETSEL, start, end); \
9424     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
9425
9426 #define check_selection(hctl, start, end) \
9427     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
9428     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
9429
9430     subclass_edit();
9431
9432     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
9433                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
9434                           0, 0, 100, 100, 0, 0, 0, NULL);
9435     ok(hdlg != 0, "Failed to create custom dialog window\n");
9436
9437     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
9438                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9439                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
9440     ok(hedit1 != 0, "Failed to create edit control\n");
9441     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
9442                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
9443                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
9444     ok(hedit2 != 0, "Failed to create edit control\n");
9445
9446     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
9447     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
9448
9449     hfocus = GetFocus();
9450     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
9451
9452     SetFocus(hedit2);
9453     hfocus = GetFocus();
9454     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
9455
9456     check_selection(hedit1, 0, 0);
9457     check_selection(hedit2, 0, 0);
9458
9459     set_selection(hedit2, 0, -1);
9460     check_selection(hedit2, 0, 3);
9461
9462     SetFocus(0);
9463     hfocus = GetFocus();
9464     ok(hfocus == 0, "wrong focus %p\n", hfocus);
9465
9466     flush_sequence();
9467     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9468     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9469     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
9470
9471     hfocus = GetFocus();
9472     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9473
9474     check_selection(hedit1, 0, 5);
9475     check_selection(hedit2, 0, 3);
9476
9477     flush_sequence();
9478     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
9479     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
9480     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
9481
9482     hfocus = GetFocus();
9483     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
9484
9485     check_selection(hedit1, 0, 5);
9486     check_selection(hedit2, 0, 3);
9487
9488     EndDialog(hdlg, 0);
9489     DestroyWindow(hedit1);
9490     DestroyWindow(hedit2);
9491     DestroyWindow(hdlg);
9492     flush_sequence();
9493
9494 #undef set_selection
9495 #undef check_selection
9496
9497     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
9498     cls.lpszClassName = "MyDialogClass";
9499     cls.hInstance = GetModuleHandle(0);
9500     /* need a cast since a dlgproc is used as a wndproc */
9501     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
9502     if (!RegisterClass(&cls)) assert(0);
9503
9504     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
9505     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9506     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
9507     EndDialog(hdlg, 0);
9508     DestroyWindow(hdlg);
9509     flush_sequence();
9510
9511     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
9512     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
9513     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
9514     EndDialog(hdlg, 0);
9515     DestroyWindow(hdlg);
9516     flush_sequence();
9517
9518     UnregisterClass(cls.lpszClassName, cls.hInstance);
9519 }
9520
9521 static void test_nullCallback(void)
9522 {
9523     HWND hwnd;
9524
9525     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9526                            100, 100, 200, 200, 0, 0, 0, NULL);
9527     ok (hwnd != 0, "Failed to create overlapped window\n");
9528
9529     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
9530     flush_events();
9531     DestroyWindow(hwnd);
9532 }
9533
9534 static const struct message SetForegroundWindowSeq[] =
9535 {
9536     { WM_NCACTIVATE, sent|wparam, 0 },
9537     { WM_GETTEXT, sent|defwinproc|optional },
9538     { WM_ACTIVATE, sent|wparam, 0 },
9539     { WM_ACTIVATEAPP, sent|wparam, 0 },
9540     { WM_KILLFOCUS, sent },
9541     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9542     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
9543     { 0 }
9544 };
9545
9546 static void test_SetForegroundWindow(void)
9547 {
9548     HWND hwnd;
9549
9550     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
9551                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9552                            100, 100, 200, 200, 0, 0, 0, NULL);
9553     ok (hwnd != 0, "Failed to create overlapped window\n");
9554     flush_sequence();
9555
9556     trace("SetForegroundWindow( 0 )\n");
9557     SetForegroundWindow( 0 );
9558     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
9559     trace("SetForegroundWindow( GetDesktopWindow() )\n");
9560     SetForegroundWindow( GetDesktopWindow() );
9561     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
9562                                         "foreground top level window", FALSE);
9563     trace("done\n");
9564
9565     DestroyWindow(hwnd);
9566 }
9567
9568 static void test_dbcs_wm_char(void)
9569 {
9570     BYTE dbch[2];
9571     WCHAR wch, bad_wch;
9572     HWND hwnd, hwnd2;
9573     MSG msg;
9574     DWORD time;
9575     POINT pt;
9576     DWORD_PTR res;
9577     CPINFOEXA cpinfo;
9578     UINT i, j, k;
9579     struct message wmCharSeq[2];
9580
9581     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
9582     if (cpinfo.MaxCharSize != 2)
9583     {
9584         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
9585         return;
9586     }
9587
9588     dbch[0] = dbch[1] = 0;
9589     wch = 0;
9590     bad_wch = cpinfo.UnicodeDefaultChar;
9591     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
9592         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
9593             for (k = 128; k <= 255; k++)
9594             {
9595                 char str[2];
9596                 WCHAR wstr[2];
9597                 str[0] = j;
9598                 str[1] = k;
9599                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
9600                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
9601                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
9602                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
9603                 {
9604                     dbch[0] = j;
9605                     dbch[1] = k;
9606                     wch = wstr[0];
9607                     break;
9608                 }
9609             }
9610
9611     if (!wch)
9612     {
9613         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
9614         return;
9615     }
9616     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
9617            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
9618
9619     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
9620                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9621     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
9622                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
9623     ok (hwnd != 0, "Failed to create overlapped window\n");
9624     ok (hwnd2 != 0, "Failed to create overlapped window\n");
9625     flush_sequence();
9626
9627     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
9628     wmCharSeq[0].message = WM_CHAR;
9629     wmCharSeq[0].flags = sent|wparam;
9630     wmCharSeq[0].wParam = wch;
9631
9632     /* posted message */
9633     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9634     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9635     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9636     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9637     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9638     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9639     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9640
9641     /* posted thread message */
9642     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
9643     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9644     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9645     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9646     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9647     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9648     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9649
9650     /* sent message */
9651     flush_sequence();
9652     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9653     ok_sequence( WmEmptySeq, "no messages", FALSE );
9654     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9655     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9656     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9657
9658     /* sent message with timeout */
9659     flush_sequence();
9660     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
9661     ok_sequence( WmEmptySeq, "no messages", FALSE );
9662     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
9663     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9664     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9665
9666     /* sent message with timeout and callback */
9667     flush_sequence();
9668     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
9669     ok_sequence( WmEmptySeq, "no messages", FALSE );
9670     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
9671     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9672     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9673
9674     /* sent message with callback */
9675     flush_sequence();
9676     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9677     ok_sequence( WmEmptySeq, "no messages", FALSE );
9678     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
9679     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9680     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9681
9682     /* direct window proc call */
9683     flush_sequence();
9684     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9685     ok_sequence( WmEmptySeq, "no messages", FALSE );
9686     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9687     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9688
9689     /* dispatch message */
9690     msg.hwnd = hwnd;
9691     msg.message = WM_CHAR;
9692     msg.wParam = dbch[0];
9693     msg.lParam = 0;
9694     DispatchMessageA( &msg );
9695     ok_sequence( WmEmptySeq, "no messages", FALSE );
9696     msg.wParam = dbch[1];
9697     DispatchMessageA( &msg );
9698     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9699
9700     /* window handle is irrelevant */
9701     flush_sequence();
9702     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9703     ok_sequence( WmEmptySeq, "no messages", FALSE );
9704     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9705     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9706     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9707
9708     /* interleaved post and send */
9709     flush_sequence();
9710     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9711     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
9712     ok_sequence( WmEmptySeq, "no messages", FALSE );
9713     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9714     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9715     ok_sequence( WmEmptySeq, "no messages", FALSE );
9716     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9717     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9718     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
9719     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9720     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9721     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9722     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9723
9724     /* interleaved sent message and winproc */
9725     flush_sequence();
9726     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9727     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9728     ok_sequence( WmEmptySeq, "no messages", FALSE );
9729     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9730     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9731     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9732     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9733
9734     /* interleaved winproc and dispatch */
9735     msg.hwnd = hwnd;
9736     msg.message = WM_CHAR;
9737     msg.wParam = dbch[0];
9738     msg.lParam = 0;
9739     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
9740     DispatchMessageA( &msg );
9741     ok_sequence( WmEmptySeq, "no messages", FALSE );
9742     msg.wParam = dbch[1];
9743     DispatchMessageA( &msg );
9744     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9745     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
9746     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9747
9748     /* interleaved sends */
9749     flush_sequence();
9750     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
9751     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
9752     ok_sequence( WmEmptySeq, "no messages", FALSE );
9753     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
9754     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9755     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
9756     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9757
9758     /* dbcs WM_CHAR */
9759     flush_sequence();
9760     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
9761     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
9762     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9763
9764     /* other char messages are not magic */
9765     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
9766     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9767     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
9768     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
9769     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9770     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
9771     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9772     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
9773     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
9774     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9775
9776     /* test retrieving messages */
9777
9778     PostMessageW( hwnd, WM_CHAR, wch, 0 );
9779     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9780     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9781     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9782     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9783     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9784     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9785     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9786     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9787     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9788
9789     /* message filters */
9790     PostMessageW( hwnd, WM_CHAR, wch, 0 );
9791     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
9792     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9793     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9794     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9795     /* message id is filtered, hwnd is not */
9796     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
9797     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
9798     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9799     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9800     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9801     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9802
9803     /* mixing GetMessage and PostMessage */
9804     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
9805     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
9806     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9807     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9808     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9809     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
9810     time = msg.time;
9811     pt = msg.pt;
9812     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
9813     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9814     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9815     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9816     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9817     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
9818     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
9819     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 );
9820     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9821
9822     /* without PM_REMOVE */
9823     PostMessageW( hwnd, WM_CHAR, wch, 0 );
9824     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
9825     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9826     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9827     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9828     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9829     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9830     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9831     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9832     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
9833     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9834     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9835     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9836     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
9837     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
9838     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
9839     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
9840     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
9841
9842     DestroyWindow(hwnd);
9843 }
9844
9845 #define ID_LISTBOX 0x000f
9846
9847 static const struct message wm_lb_setcursel_0[] =
9848 {
9849     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
9850     { WM_CTLCOLORLISTBOX, sent|parent },
9851     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
9852     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
9853     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
9854     { 0 }
9855 };
9856 static const struct message wm_lb_setcursel_1[] =
9857 {
9858     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
9859     { WM_CTLCOLORLISTBOX, sent|parent },
9860     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
9861     { WM_CTLCOLORLISTBOX, sent|parent },
9862     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
9863     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
9864     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
9865     { 0 }
9866 };
9867 static const struct message wm_lb_setcursel_2[] =
9868 {
9869     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
9870     { WM_CTLCOLORLISTBOX, sent|parent },
9871     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
9872     { WM_CTLCOLORLISTBOX, sent|parent },
9873     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
9874     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
9875     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
9876     { 0 }
9877 };
9878 static const struct message wm_lb_click_0[] =
9879 {
9880     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
9881     { HCBT_SETFOCUS, hook },
9882     { WM_KILLFOCUS, sent|parent },
9883     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
9884     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9885     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9886     { WM_SETFOCUS, sent },
9887
9888     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
9889     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
9890     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
9891     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
9892     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9893
9894     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
9895     { WM_CTLCOLORLISTBOX, sent|parent },
9896     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
9897     { WM_CTLCOLORLISTBOX, sent|parent },
9898     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
9899     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
9900
9901     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
9902     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
9903
9904     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9905     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9906     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, 0 },
9907     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
9908     { 0 }
9909 };
9910
9911 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
9912
9913 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
9914
9915 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9916 {
9917     struct message msg;
9918
9919     /* do not log painting messages */
9920     if (message != WM_PAINT &&
9921         message != WM_NCPAINT &&
9922         message != WM_SYNCPAINT &&
9923         message != WM_ERASEBKGND &&
9924         message != WM_NCHITTEST &&
9925         message != WM_GETTEXT &&
9926         message != WM_GETICON &&
9927         message != WM_DEVICECHANGE)
9928     {
9929         trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
9930
9931         msg.message = message;
9932         msg.flags = sent|wparam|lparam;
9933         msg.wParam = wp;
9934         msg.lParam = lp;
9935         add_message(&msg);
9936     }
9937
9938     return CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
9939 }
9940
9941 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
9942                                int caret_index, int top_index, int line)
9943 {
9944     LRESULT ret;
9945
9946     /* calling an orig proc helps to avoid unnecessary message logging */
9947     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
9948     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
9949     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
9950     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
9951     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
9952     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
9953     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
9954     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
9955 }
9956
9957 static void test_listbox(void)
9958 {
9959     HWND parent, listbox;
9960     LRESULT ret;
9961
9962     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
9963                              100, 100, 200, 200, 0, 0, 0, NULL);
9964     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
9965                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
9966                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
9967     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
9968
9969     check_lb_state(listbox, 0, LB_ERR, 0, 0);
9970
9971     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
9972     ok(ret == 0, "expected 0, got %ld\n", ret);
9973     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
9974     ok(ret == 1, "expected 1, got %ld\n", ret);
9975     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
9976     ok(ret == 2, "expected 2, got %ld\n", ret);
9977
9978     check_lb_state(listbox, 3, LB_ERR, 0, 0);
9979
9980     flush_sequence();
9981
9982     log_all_parent_messages++;
9983
9984     trace("selecting item 0\n");
9985     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
9986     ok(ret == 0, "expected 0, got %ld\n", ret);
9987     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
9988     check_lb_state(listbox, 3, 0, 0, 0);
9989     flush_sequence();
9990
9991     trace("selecting item 1\n");
9992     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
9993     ok(ret == 1, "expected 1, got %ld\n", ret);
9994     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
9995     check_lb_state(listbox, 3, 1, 1, 0);
9996
9997     trace("selecting item 2\n");
9998     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
9999     ok(ret == 2, "expected 2, got %ld\n", ret);
10000     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
10001     check_lb_state(listbox, 3, 2, 2, 0);
10002
10003     trace("clicking on item 0\n");
10004     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
10005     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10006     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
10007     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10008     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
10009     check_lb_state(listbox, 3, 0, 0, 0);
10010     flush_sequence();
10011
10012     log_all_parent_messages--;
10013
10014     DestroyWindow(parent);
10015 }
10016
10017 START_TEST(msg)
10018 {
10019     BOOL ret;
10020     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
10021
10022     init_procs();
10023
10024     if (!RegisterWindowClasses()) assert(0);
10025
10026     if (pSetWinEventHook)
10027     {
10028         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
10029                                                       GetModuleHandleA(0),
10030                                                       win_event_proc,
10031                                                       0,
10032                                                       GetCurrentThreadId(),
10033                                                       WINEVENT_INCONTEXT);
10034         assert(hEvent_hook);
10035
10036         if (pIsWinEventHookInstalled)
10037         {
10038             UINT event;
10039             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
10040                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
10041         }
10042     }
10043
10044     cbt_hook_thread_id = GetCurrentThreadId();
10045     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
10046     assert(hCBT_hook);
10047
10048     test_winevents();
10049
10050     /* Fix message sequences before removing 4 lines below */
10051 #if 1
10052     if (pUnhookWinEvent && hEvent_hook)
10053     {
10054         ret = pUnhookWinEvent(hEvent_hook);
10055         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10056         pUnhookWinEvent = 0;
10057     }
10058     hEvent_hook = 0;
10059 #endif
10060
10061     test_ShowWindow();
10062     test_PeekMessage();
10063     test_PeekMessage2();
10064     test_scrollwindowex();
10065     test_messages();
10066     test_showwindow();
10067     invisible_parent_tests();
10068     test_mdi_messages();
10069     test_button_messages();
10070     test_static_messages();
10071     test_paint_messages();
10072     test_interthread_messages();
10073     test_message_conversion();
10074     test_accelerators();
10075     test_timers();
10076     test_timers_no_wnd();
10077     test_set_hook();
10078     test_DestroyWindow();
10079     test_DispatchMessage();
10080     test_SendMessageTimeout();
10081     test_edit_messages();
10082     test_quit_message();
10083
10084     if (!pTrackMouseEvent)
10085         skip("TrackMouseEvent is not available\n");
10086     else
10087         test_TrackMouseEvent();
10088
10089     test_SetWindowRgn();
10090     test_sys_menu();
10091     test_dialog_messages();
10092     test_nullCallback();
10093     test_SetForegroundWindow();
10094     test_dbcs_wm_char();
10095     test_listbox();
10096
10097     UnhookWindowsHookEx(hCBT_hook);
10098     if (pUnhookWinEvent)
10099     {
10100         ret = pUnhookWinEvent(hEvent_hook);
10101         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10102         SetLastError(0xdeadbeef);
10103         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
10104         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10105            GetLastError() == 0xdeadbeef, /* Win9x */
10106            "unexpected error %d\n", GetLastError());
10107     }
10108     else
10109         skip("UnhookWinEvent is not available\n");
10110 }