winejoystick.drv: Use CP_UNIXCP instead of CP_ACP when converting a string that comes...
[wine] / dlls / user32 / tests / msg.c
1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004, 2005 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE        0x0800
41 #define SWP_NOCLIENTMOVE        0x1000
42 #define SWP_STATECHANGED        0x8000
43
44 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
45
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER         0x0118
52 #endif
53
54 #define WND_PARENT_ID           1
55 #define WND_POPUP_ID            2
56 #define WND_CHILD_ID            3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61
62 /* encoded DRAWITEMSTRUCT into an LPARAM */
63 typedef struct
64 {
65     union
66     {
67         struct
68         {
69             UINT type    : 4;  /* ODT_* flags */
70             UINT ctl_id  : 4;  /* Control ID */
71             UINT item_id : 4;  /* Menu item ID */
72             UINT action  : 4;  /* ODA_* flags */
73             UINT state   : 16; /* ODS_* flags */
74         } item;
75         LPARAM lp;
76     } u;
77 } DRAW_ITEM_STRUCT;
78
79 static BOOL test_DestroyWindow_flag;
80 static HWINEVENTHOOK hEvent_hook;
81 static HHOOK hCBT_hook;
82 static DWORD cbt_hook_thread_id;
83
84 static const WCHAR testWindowClassW[] =
85 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
86
87 /*
88 FIXME: add tests for these
89 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
90  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
91  WS_THICKFRAME: thick border
92  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
93  WS_BORDER (default for overlapped windows): single black border
94  none (default for child (and popup?) windows): no border
95 */
96
97 typedef enum {
98     sent=0x1,
99     posted=0x2,
100     parent=0x4,
101     wparam=0x8,
102     lparam=0x10,
103     defwinproc=0x20,
104     beginpaint=0x40,
105     optional=0x80,
106     hook=0x100,
107     winevent_hook=0x200
108 } msg_flags_t;
109
110 struct message {
111     UINT message;          /* the WM_* code */
112     msg_flags_t flags;     /* message props */
113     WPARAM wParam;         /* expected value of wParam */
114     LPARAM lParam;         /* expected value of lParam */
115     WPARAM wp_mask;        /* mask for wParam checks */
116     LPARAM lp_mask;        /* mask for lParam checks */
117 };
118
119 struct recvd_message {
120     UINT message;          /* the WM_* code */
121     msg_flags_t flags;     /* message props */
122     HWND hwnd;             /* window that received the message */
123     WPARAM wParam;         /* expected value of wParam */
124     LPARAM lParam;         /* expected value of lParam */
125     int line;              /* source line where logged */
126     const char *descr;     /* description for trace output */
127     char output[512];      /* trace output */
128 };
129
130 /* Empty message sequence */
131 static const struct message WmEmptySeq[] =
132 {
133     { 0 }
134 };
135 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
136 static const struct message WmCreateOverlappedSeq[] = {
137     { HCBT_CREATEWND, hook },
138     { WM_GETMINMAXINFO, sent },
139     { WM_NCCREATE, sent },
140     { WM_NCCALCSIZE, sent|wparam, 0 },
141     { 0x0093, sent|defwinproc|optional },
142     { 0x0094, sent|defwinproc|optional },
143     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
144     { WM_CREATE, sent },
145     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
146     { 0 }
147 };
148 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
149  * for a not visible overlapped window.
150  */
151 static const struct message WmSWP_ShowOverlappedSeq[] = {
152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
153     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
154     { WM_NCPAINT, sent|wparam|optional, 1 },
155     { WM_GETTEXT, sent|defwinproc|optional },
156     { WM_ERASEBKGND, sent|optional },
157     { HCBT_ACTIVATE, hook },
158     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
159     { WM_NOTIFYFORMAT, sent|optional },
160     { WM_QUERYUISTATE, sent|optional },
161     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
162     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
163     { WM_ACTIVATEAPP, sent|wparam, 1 },
164     { WM_NCACTIVATE, sent|wparam, 1 },
165     { WM_GETTEXT, sent|defwinproc|optional },
166     { WM_ACTIVATE, sent|wparam, 1 },
167     { HCBT_SETFOCUS, hook },
168     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
169     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
170     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
171     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
172     { WM_GETTEXT, sent|optional },
173     { WM_NCPAINT, sent|wparam|optional, 1 },
174     { WM_GETTEXT, sent|defwinproc|optional },
175     { WM_ERASEBKGND, sent|optional },
176     /* Win9x adds SWP_NOZORDER below */
177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
178     { WM_GETTEXT, sent|optional },
179     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
180     { WM_NCPAINT, sent|wparam|optional, 1 },
181     { WM_ERASEBKGND, sent|optional },
182     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
183     { WM_PAINT, sent|optional },
184     { WM_NCPAINT, sent|beginpaint|optional },
185     { WM_ERASEBKGND, sent|beginpaint|optional },
186     { 0 }
187 };
188 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
189  * for a visible overlapped window.
190  */
191 static const struct message WmSWP_HideOverlappedSeq[] = {
192     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
193     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
194     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
195     { 0 }
196 };
197
198 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
199  * for a visible overlapped window.
200  */
201 static const struct message WmSWP_ResizeSeq[] = {
202     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
203     { WM_GETMINMAXINFO, sent|defwinproc },
204     { WM_NCCALCSIZE, sent|wparam, TRUE },
205     { WM_NCPAINT, sent|optional },
206     { WM_GETTEXT, sent|defwinproc|optional },
207     { WM_ERASEBKGND, sent|optional },
208     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
209     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
210     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
211     { WM_NCPAINT, sent|optional },
212     { WM_GETTEXT, sent|defwinproc|optional },
213     { WM_ERASEBKGND, sent|optional },
214     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
215     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
216     { 0 }
217 };
218
219 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
220  * for a visible popup window.
221  */
222 static const struct message WmSWP_ResizePopupSeq[] = {
223     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
224     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
225     { WM_NCCALCSIZE, sent|wparam, TRUE },
226     { WM_NCPAINT, sent|optional },
227     { WM_GETTEXT, sent|defwinproc|optional },
228     { WM_ERASEBKGND, sent|optional },
229     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
230     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
231     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
232     { WM_NCPAINT, sent|optional },
233     { WM_GETTEXT, sent|defwinproc|optional },
234     { WM_ERASEBKGND, sent|optional },
235     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
236     { 0 }
237 };
238
239 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
240  * for a visible overlapped window.
241  */
242 static const struct message WmSWP_MoveSeq[] = {
243     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
244     { WM_NCPAINT, sent|optional },
245     { WM_GETTEXT, sent|defwinproc|optional },
246     { WM_ERASEBKGND, sent|optional },
247     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
248     { WM_MOVE, sent|defwinproc|wparam, 0 },
249     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
250     { 0 }
251 };
252 /* Resize with SetWindowPos(SWP_NOZORDER)
253  * for a visible overlapped window
254  * SWP_NOZORDER is stripped by the logging code
255  */
256 static const struct message WmSWP_ResizeNoZOrder[] = {
257     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
258     { WM_GETMINMAXINFO, sent|defwinproc },
259     { WM_NCCALCSIZE, sent|wparam, 1 },
260     { WM_NCPAINT, sent },
261     { WM_GETTEXT, sent|defwinproc|optional },
262     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
263     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE },
264     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
265     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
266     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
267     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
268     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
269     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
270     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
271     { 0 }
272 };
273
274 /* Switch visible mdi children */
275 static const struct message WmSwitchChild[] = {
276     /* Switch MDI child */
277     { WM_MDIACTIVATE, sent },/* in the MDI client */
278     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
279     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
280     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
281     /* Deactivate 2nd MDI child */
282     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
283     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
284     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
285     /* Preparing for maximize and maximaze the 1st MDI child */
286     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
287     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
288     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
289     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
290     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
291     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
292     /* Lock redraw 2nd MDI child */
293     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
294     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
295     /* Restore 2nd MDI child */
296     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
297     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
298     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
299     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
300     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
301     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
302     /* Redraw 2nd MDI child */
303     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
304     /* Redraw MDI frame */
305     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
306     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
307     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
308     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
309     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
310     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
311     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
312     { HCBT_SETFOCUS, hook },
313     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
314     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
315     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
316     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
317     { WM_SETFOCUS, sent },/* in the MDI client */
318     { HCBT_SETFOCUS, hook },
319     { WM_KILLFOCUS, sent },/* in the MDI client */
320     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
321     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
322     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
323     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
324     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
325     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
326     { 0 }
327 };
328
329 /* Switch visible not maximized mdi children */
330 static const struct message WmSwitchNotMaximizedChild[] = {
331     /* Switch not maximized MDI child */
332     { WM_MDIACTIVATE, sent },/* in the MDI client */
333     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
334     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
335     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
336     /* Deactivate 1st MDI child */
337     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
338     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
339     /* Activate 2nd MDI child */
340     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
341     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
342     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
343     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
344     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
345     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
346     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
347     { HCBT_SETFOCUS, hook },
348     { WM_KILLFOCUS, sent }, /* in the  MDI client */
349     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
350     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
351     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
352     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
353     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
354     { 0 }
355 };
356
357
358 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
359                 SWP_NOZORDER|SWP_FRAMECHANGED)
360  * for a visible overlapped window with WS_CLIPCHILDREN style set.
361  */
362 static const struct message WmSWP_FrameChanged_clip[] = {
363     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
364     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
365     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
366     { WM_GETTEXT, sent|parent|defwinproc|optional },
367     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
368     { WM_NCPAINT, sent }, /* wparam != 1 */
369     { WM_ERASEBKGND, sent },
370     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
371     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
372     { WM_PAINT, sent },
373     { 0 }
374 };
375 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
376                 SWP_NOZORDER|SWP_FRAMECHANGED)
377  * for a visible overlapped window.
378  */
379 static const struct message WmSWP_FrameChangedDeferErase[] = {
380     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
381     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
382     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
383     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
384     { WM_PAINT, sent|parent },
385     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
386     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
387     { WM_PAINT, sent },
388     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
389     { WM_ERASEBKGND, sent|beginpaint },
390     { 0 }
391 };
392
393 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
394                 SWP_NOZORDER|SWP_FRAMECHANGED)
395  * for a visible overlapped window without WS_CLIPCHILDREN style set.
396  */
397 static const struct message WmSWP_FrameChanged_noclip[] = {
398     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
399     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
400     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
401     { WM_GETTEXT, sent|parent|defwinproc|optional },
402     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
403     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
404     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
405     { WM_PAINT, sent },
406     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
407     { WM_ERASEBKGND, sent|beginpaint },
408     { 0 }
409 };
410
411 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
412 static const struct message WmShowOverlappedSeq[] = {
413     { WM_SHOWWINDOW, sent|wparam, 1 },
414     { WM_NCPAINT, sent|wparam|optional, 1 },
415     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
416     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
417     { WM_NCPAINT, sent|wparam|optional, 1 },
418     { WM_GETTEXT, sent|defwinproc|optional },
419     { WM_ERASEBKGND, sent|optional },
420     { HCBT_ACTIVATE, hook },
421     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
422     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
423     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
424     { WM_NCPAINT, sent|wparam|optional, 1 },
425     { WM_ACTIVATEAPP, sent|wparam, 1 },
426     { WM_NCACTIVATE, sent|wparam, 1 },
427     { WM_GETTEXT, sent|defwinproc|optional },
428     { WM_ACTIVATE, sent|wparam, 1 },
429     { HCBT_SETFOCUS, hook },
430     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
431     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
432     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
433     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
434     { WM_GETTEXT, sent|optional },
435     { WM_NCPAINT, sent|wparam|optional, 1 },
436     { WM_GETTEXT, sent|defwinproc|optional },
437     { WM_ERASEBKGND, sent|optional },
438     /* Win9x adds SWP_NOZORDER below */
439     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
440     { WM_NCCALCSIZE, sent|optional },
441     { WM_GETTEXT, sent|optional },
442     { WM_NCPAINT, sent|optional },
443     { WM_ERASEBKGND, sent|optional },
444 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
445        * messages. Does that mean that CreateWindow doesn't set initial
446        * window dimensions for overlapped windows?
447        */
448     { WM_SIZE, sent },
449     { WM_MOVE, sent },
450 #endif
451     { WM_PAINT, sent|optional },
452     { WM_NCPAINT, sent|beginpaint|optional },
453     { 0 }
454 };
455 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
456 static const struct message WmShowMaxOverlappedSeq[] = {
457     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
458     { WM_GETMINMAXINFO, sent },
459     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
460     { WM_GETMINMAXINFO, sent|defwinproc },
461     { WM_NCCALCSIZE, sent|wparam, TRUE },
462     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
463     { HCBT_ACTIVATE, hook },
464     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
465     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
466     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
467     { WM_ACTIVATEAPP, sent|wparam, 1 },
468     { WM_NCACTIVATE, sent|wparam, 1 },
469     { WM_GETTEXT, sent|defwinproc|optional },
470     { WM_ACTIVATE, sent|wparam, 1 },
471     { HCBT_SETFOCUS, hook },
472     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
473     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
474     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
475     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
476     { WM_GETTEXT, sent|optional },
477     { WM_NCPAINT, sent|wparam|optional, 1 },
478     { WM_GETTEXT, sent|defwinproc|optional },
479     { WM_ERASEBKGND, sent|optional },
480     /* Win9x adds SWP_NOZORDER below */
481     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
482     { WM_MOVE, sent|defwinproc },
483     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
484     { WM_GETTEXT, sent|optional },
485     { WM_NCCALCSIZE, sent|optional },
486     { WM_NCPAINT, sent|optional },
487     { WM_ERASEBKGND, sent|optional },
488     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
489     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
490     { WM_PAINT, sent|optional },
491     { WM_NCPAINT, sent|beginpaint|optional },
492     { WM_ERASEBKGND, sent|beginpaint|optional },
493     { 0 }
494 };
495 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
496 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
497     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
498     { WM_GETTEXT, sent|optional },
499     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
500     { WM_GETMINMAXINFO, sent|defwinproc },
501     { WM_NCCALCSIZE, sent|wparam, TRUE },
502     { WM_NCPAINT, sent|optional },
503     { WM_GETTEXT, sent|defwinproc|optional },
504     { WM_ERASEBKGND, sent|optional },
505     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
506     { WM_MOVE, sent|defwinproc|optional },
507     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
508     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
509     { WM_NCPAINT, sent|optional },
510     { WM_ERASEBKGND, sent|optional },
511     { WM_PAINT, sent|optional },
512     { WM_NCPAINT, sent|beginpaint|optional },
513     { WM_ERASEBKGND, sent|beginpaint|optional },
514     { 0 }
515 };
516 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
517 static const struct message WmShowRestoreMinOverlappedSeq[] = {
518     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
519     { WM_QUERYOPEN, sent|optional },
520     { WM_GETTEXT, sent|optional },
521     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
522     { WM_GETMINMAXINFO, sent|defwinproc },
523     { WM_NCCALCSIZE, sent|wparam, TRUE },
524     { HCBT_ACTIVATE, hook },
525     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
526     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
527     { WM_ACTIVATEAPP, sent|wparam, 1 },
528     { WM_NCACTIVATE, sent|wparam, 1 },
529     { WM_GETTEXT, sent|defwinproc|optional },
530     { WM_ACTIVATE, sent|wparam, 1 },
531     { HCBT_SETFOCUS, hook },
532     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
533     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
534     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
535     { WM_GETTEXT, sent|optional },
536     { WM_NCPAINT, sent|wparam|optional, 1 },
537     { WM_GETTEXT, sent|defwinproc|optional },
538     { WM_ERASEBKGND, sent },
539     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
540     { WM_MOVE, sent|defwinproc },
541     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
542     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
543     { WM_NCPAINT, sent|wparam|optional, 1 },
544     { WM_ERASEBKGND, sent|optional },
545     { WM_ACTIVATE, sent|wparam, 1 },
546     { WM_GETTEXT, sent|optional },
547     { WM_PAINT, sent|optional },
548     { WM_NCPAINT, sent|beginpaint|optional },
549     { WM_ERASEBKGND, sent|beginpaint|optional },
550     { 0 }
551 };
552 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
553 static const struct message WmShowMinOverlappedSeq[] = {
554     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
555     { HCBT_SETFOCUS, hook },
556     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
557     { WM_KILLFOCUS, sent },
558     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
559     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
560     { WM_GETTEXT, sent|optional },
561     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
562     { WM_GETMINMAXINFO, sent|defwinproc },
563     { WM_NCCALCSIZE, sent|wparam, TRUE },
564     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
565     { WM_NCPAINT, sent|optional },
566     { WM_GETTEXT, sent|defwinproc|optional },
567     { WM_WINDOWPOSCHANGED, sent },
568     { WM_MOVE, sent|defwinproc },
569     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
570     { WM_NCCALCSIZE, sent|optional },
571     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
572     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
573     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
574     { WM_NCACTIVATE, sent|wparam, 0 },
575     { WM_GETTEXT, sent|defwinproc|optional },
576     { WM_ACTIVATE, sent },
577     { WM_ACTIVATEAPP, sent|wparam, 0 },
578     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
579     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
580     { WM_PAINT, sent|optional },
581     { WM_NCPAINT, sent|beginpaint|optional },
582     { WM_ERASEBKGND, sent|beginpaint|optional },
583     { 0 }
584 };
585 /* ShowWindow(SW_HIDE) for a visible overlapped window */
586 static const struct message WmHideOverlappedSeq[] = {
587     { WM_SHOWWINDOW, sent|wparam, 0 },
588     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
589     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
590     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
591     { WM_SIZE, sent|optional }, /* XP doesn't send it */
592     { WM_MOVE, sent|optional }, /* XP doesn't send it */
593     { WM_NCACTIVATE, sent|wparam, 0 },
594     { WM_ACTIVATE, sent|wparam, 0 },
595     { WM_ACTIVATEAPP, sent|wparam, 0 },
596     { WM_KILLFOCUS, sent|wparam, 0 },
597     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
598     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
599     { 0 }
600 };
601 /* DestroyWindow for a visible overlapped window */
602 static const struct message WmDestroyOverlappedSeq[] = {
603     { HCBT_DESTROYWND, hook },
604     { 0x0090, sent|optional },
605     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
606     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
607     { 0x0090, sent|optional },
608     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
609     { WM_NCACTIVATE, sent|optional|wparam, 0 },
610     { WM_ACTIVATE, sent|optional|wparam, 0 },
611     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
612     { WM_KILLFOCUS, sent|optional|wparam, 0 },
613     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
614     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
615     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
616     { WM_DESTROY, sent },
617     { WM_NCDESTROY, sent },
618     { 0 }
619 };
620 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
621 static const struct message WmCreateMaxPopupSeq[] = {
622     { HCBT_CREATEWND, hook },
623     { WM_NCCREATE, sent },
624     { WM_NCCALCSIZE, sent|wparam, 0 },
625     { WM_CREATE, sent },
626     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
627     { WM_SIZE, sent|wparam, SIZE_RESTORED },
628     { WM_MOVE, sent },
629     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
630     { WM_GETMINMAXINFO, sent },
631     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
632     { WM_NCCALCSIZE, sent|wparam, TRUE },
633     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
634     { WM_MOVE, sent|defwinproc },
635     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
636     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
637     { WM_SHOWWINDOW, sent|wparam, 1 },
638     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
639     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
640     { HCBT_ACTIVATE, hook },
641     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
642     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
643     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
644     { WM_NCPAINT, sent|wparam|optional, 1 },
645     { WM_ERASEBKGND, sent|optional },
646     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
647     { WM_ACTIVATEAPP, sent|wparam, 1 },
648     { WM_NCACTIVATE, sent|wparam, 1 },
649     { WM_ACTIVATE, sent|wparam, 1 },
650     { HCBT_SETFOCUS, hook },
651     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
652     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
653     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
654     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
655     { WM_GETTEXT, sent|optional },
656     { WM_SYNCPAINT, sent|wparam|optional, 4 },
657     { WM_NCPAINT, sent|wparam|optional, 1 },
658     { WM_ERASEBKGND, sent|optional },
659     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
660     { WM_ERASEBKGND, sent|defwinproc|optional },
661     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
662     { 0 }
663 };
664 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
665 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
666     { HCBT_CREATEWND, hook },
667     { WM_NCCREATE, sent },
668     { WM_NCCALCSIZE, sent|wparam, 0 },
669     { WM_CREATE, sent },
670     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
671     { WM_SIZE, sent|wparam, SIZE_RESTORED },
672     { WM_MOVE, sent },
673     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
674     { WM_GETMINMAXINFO, sent },
675     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
676     { WM_NCCALCSIZE, sent|wparam, TRUE },
677     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
678     { WM_MOVE, sent|defwinproc },
679     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
680     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
681     { 0 }
682 };
683 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
684 static const struct message WmShowMaxPopupResizedSeq[] = {
685     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
686     { WM_GETMINMAXINFO, sent },
687     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
688     { WM_NCCALCSIZE, sent|wparam, TRUE },
689     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
690     { HCBT_ACTIVATE, hook },
691     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
692     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
693     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
694     { WM_NCPAINT, sent|wparam|optional, 1 },
695     { WM_ERASEBKGND, sent|optional },
696     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
697     { WM_ACTIVATEAPP, sent|wparam, 1 },
698     { WM_NCACTIVATE, sent|wparam, 1 },
699     { WM_ACTIVATE, sent|wparam, 1 },
700     { HCBT_SETFOCUS, hook },
701     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
702     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
703     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
704     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
705     { WM_GETTEXT, sent|optional },
706     { WM_NCPAINT, sent|wparam|optional, 1 },
707     { WM_ERASEBKGND, sent|optional },
708     { WM_WINDOWPOSCHANGED, sent },
709     /* WinNT4.0 sends WM_MOVE */
710     { WM_MOVE, sent|defwinproc|optional },
711     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
712     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
713     { 0 }
714 };
715 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
716 static const struct message WmShowMaxPopupSeq[] = {
717     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
718     { WM_GETMINMAXINFO, sent },
719     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
720     { WM_NCCALCSIZE, sent|wparam, TRUE },
721     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
722     { HCBT_ACTIVATE, hook },
723     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
724     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
725     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
726     { WM_ACTIVATEAPP, sent|wparam, 1 },
727     { WM_NCACTIVATE, sent|wparam, 1 },
728     { WM_ACTIVATE, sent|wparam, 1 },
729     { HCBT_SETFOCUS, hook },
730     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
731     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
732     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
733     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
734     { WM_GETTEXT, sent|optional },
735     { WM_SYNCPAINT, sent|wparam|optional, 4 },
736     { WM_NCPAINT, sent|wparam|optional, 1 },
737     { WM_ERASEBKGND, sent|optional },
738     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
739     { WM_ERASEBKGND, sent|defwinproc|optional },
740     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
741     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
742     { 0 }
743 };
744 /* CreateWindow(WS_VISIBLE) for popup window */
745 static const struct message WmCreatePopupSeq[] = {
746     { HCBT_CREATEWND, hook },
747     { WM_NCCREATE, sent },
748     { WM_NCCALCSIZE, sent|wparam, 0 },
749     { WM_CREATE, sent },
750     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
751     { WM_SIZE, sent|wparam, SIZE_RESTORED },
752     { WM_MOVE, sent },
753     { WM_SHOWWINDOW, sent|wparam, 1 },
754     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
755     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
756     { HCBT_ACTIVATE, hook },
757     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
758     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
759     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
760     { WM_NCPAINT, sent|wparam|optional, 1 },
761     { WM_ERASEBKGND, sent|optional },
762     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
763     { WM_ACTIVATEAPP, sent|wparam, 1 },
764     { WM_NCACTIVATE, sent|wparam, 1 },
765     { WM_ACTIVATE, sent|wparam, 1 },
766     { HCBT_SETFOCUS, hook },
767     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
768     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
769     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
770     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
771     { WM_GETTEXT, sent|optional },
772     { WM_SYNCPAINT, sent|wparam|optional, 4 },
773     { WM_NCPAINT, sent|wparam|optional, 1 },
774     { WM_ERASEBKGND, sent|optional },
775     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
776     { 0 }
777 };
778 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
779 static const struct message WmShowVisMaxPopupSeq[] = {
780     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
781     { WM_GETMINMAXINFO, sent },
782     { WM_GETTEXT, sent|optional },
783     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
784     { WM_GETTEXT, sent|optional },
785     { WM_NCCALCSIZE, sent|wparam, TRUE },
786     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
787     { WM_NCPAINT, sent|wparam|optional, 1 },
788     { WM_ERASEBKGND, sent|optional },
789     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
790     { WM_MOVE, sent|defwinproc },
791     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
792     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
793     { 0 }
794 };
795 /* CreateWindow (for a child popup window, not initially visible) */
796 static const struct message WmCreateChildPopupSeq[] = {
797     { HCBT_CREATEWND, hook },
798     { WM_NCCREATE, sent }, 
799     { WM_NCCALCSIZE, sent|wparam, 0 },
800     { WM_CREATE, sent },
801     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
802     { WM_SIZE, sent|wparam, SIZE_RESTORED },
803     { WM_MOVE, sent },
804     { 0 }
805 };
806 /* CreateWindow (for a popup window, not initially visible,
807  * which sets WS_VISIBLE in WM_CREATE handler)
808  */
809 static const struct message WmCreateInvisiblePopupSeq[] = {
810     { HCBT_CREATEWND, hook },
811     { WM_NCCREATE, sent }, 
812     { WM_NCCALCSIZE, sent|wparam, 0 },
813     { WM_CREATE, sent },
814     { WM_STYLECHANGING, sent },
815     { WM_STYLECHANGED, sent },
816     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
817     { WM_SIZE, sent|wparam, SIZE_RESTORED },
818     { WM_MOVE, sent },
819     { 0 }
820 };
821 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
822  * for a popup window with WS_VISIBLE style set
823  */
824 static const struct message WmShowVisiblePopupSeq_2[] = {
825     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
826     { 0 }
827 };
828 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
829  * for a popup window with WS_VISIBLE style set
830  */
831 static const struct message WmShowVisiblePopupSeq_3[] = {
832     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
833     { HCBT_ACTIVATE, hook },
834     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
835     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
836     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
837     { WM_NCACTIVATE, sent|wparam, 1 },
838     { WM_ACTIVATE, sent|wparam, 1 },
839     { HCBT_SETFOCUS, hook },
840     { WM_KILLFOCUS, sent|parent },
841     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
842     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
843     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
844     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
845     { WM_SETFOCUS, sent|defwinproc },
846     { WM_GETTEXT, sent|optional },
847     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
848     { 0 }
849 };
850 /* CreateWindow (for child window, not initially visible) */
851 static const struct message WmCreateChildSeq[] = {
852     { HCBT_CREATEWND, hook },
853     { WM_NCCREATE, sent }, 
854     /* child is inserted into parent's child list after WM_NCCREATE returns */
855     { WM_NCCALCSIZE, sent|wparam, 0 },
856     { WM_CREATE, sent },
857     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
858     { WM_SIZE, sent|wparam, SIZE_RESTORED },
859     { WM_MOVE, sent },
860     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
861     { 0 }
862 };
863 /* CreateWindow (for maximized child window, not initially visible) */
864 static const struct message WmCreateMaximizedChildSeq[] = {
865     { HCBT_CREATEWND, hook },
866     { WM_NCCREATE, sent }, 
867     { WM_NCCALCSIZE, sent|wparam, 0 },
868     { WM_CREATE, sent },
869     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
870     { WM_SIZE, sent|wparam, SIZE_RESTORED },
871     { WM_MOVE, sent },
872     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
873     { WM_GETMINMAXINFO, sent },
874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
875     { WM_NCCALCSIZE, sent|wparam, 1 },
876     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
877     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
878     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
879     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
880     { 0 }
881 };
882 /* CreateWindow (for a child window, initially visible) */
883 static const struct message WmCreateVisibleChildSeq[] = {
884     { HCBT_CREATEWND, hook },
885     { WM_NCCREATE, sent }, 
886     /* child is inserted into parent's child list after WM_NCCREATE returns */
887     { WM_NCCALCSIZE, sent|wparam, 0 },
888     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
889     { WM_CREATE, sent },
890     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
891     { WM_SIZE, sent|wparam, SIZE_RESTORED },
892     { WM_MOVE, sent },
893     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
894     { WM_SHOWWINDOW, sent|wparam, 1 },
895     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
896     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
897     { WM_ERASEBKGND, sent|parent|optional },
898     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
899     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
900     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
901     { 0 }
902 };
903 /* ShowWindow(SW_SHOW) for a not visible child window */
904 static const struct message WmShowChildSeq[] = {
905     { WM_SHOWWINDOW, sent|wparam, 1 },
906     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
907     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
908     { WM_ERASEBKGND, sent|parent|optional },
909     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
910     { 0 }
911 };
912 /* ShowWindow(SW_HIDE) for a visible child window */
913 static const struct message WmHideChildSeq[] = {
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     { 0 }
920 };
921 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
922 static const struct message WmHideChildSeq2[] = {
923     { WM_SHOWWINDOW, sent|wparam, 0 },
924     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
925     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
926     { WM_ERASEBKGND, sent|parent|optional },
927     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
928     { 0 }
929 };
930 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
931  * for a not visible child window
932  */
933 static const struct message WmShowChildSeq_2[] = {
934     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
935     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
936     { WM_CHILDACTIVATE, sent },
937     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
938     { 0 }
939 };
940 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
941  * for a not visible child window
942  */
943 static const struct message WmShowChildSeq_3[] = {
944     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
945     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
946     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
947     { 0 }
948 };
949 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
950  * for a visible child window with a caption
951  */
952 static const struct message WmShowChildSeq_4[] = {
953     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
954     { WM_CHILDACTIVATE, sent },
955     { 0 }
956 };
957 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
958 static const struct message WmShowChildInvisibleParentSeq_1[] = {
959     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
960     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
961     { WM_NCCALCSIZE, sent|wparam, 1 },
962     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
963     { WM_CHILDACTIVATE, sent|optional },
964     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
965     { WM_MOVE, sent|defwinproc },
966     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
967     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
968     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
969     /* FIXME: Wine creates an icon/title window while Windows doesn't */
970     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
971     { WM_GETTEXT, sent|optional },
972     { 0 }
973 };
974 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
975 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
976     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
977     { 0 }
978 };
979 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
980 static const struct message WmShowChildInvisibleParentSeq_2[] = {
981     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
982     { WM_GETMINMAXINFO, sent },
983     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
984     { WM_NCCALCSIZE, sent|wparam, 1 },
985     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
986     { WM_CHILDACTIVATE, sent },
987     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
988     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
989     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
990     { 0 }
991 };
992 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
993 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
994     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
995     { 0 }
996 };
997 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
998 static const struct message WmShowChildInvisibleParentSeq_3[] = {
999     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1000     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1001     { WM_NCCALCSIZE, sent|wparam, 1 },
1002     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1003     { WM_CHILDACTIVATE, sent },
1004     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1005     { WM_MOVE, sent|defwinproc },
1006     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1007     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1008     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1009     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1010     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1011     { WM_GETTEXT, sent|optional },
1012     { 0 }
1013 };
1014 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1015 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1016     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1017     { 0 }
1018 };
1019 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1020 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1021     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1022     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1023     { WM_NCCALCSIZE, sent|wparam, 1 },
1024     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1025     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1026     { WM_MOVE, sent|defwinproc },
1027     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1028     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1029     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1030     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1031     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1032     { WM_GETTEXT, sent|optional },
1033     { 0 }
1034 };
1035 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1036 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1037     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1038     { 0 }
1039 };
1040 /* ShowWindow(SW_SHOW) for child with invisible parent */
1041 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1042     { WM_SHOWWINDOW, sent|wparam, 1 },
1043     { 0 }
1044 };
1045 /* ShowWindow(SW_HIDE) for child with invisible parent */
1046 static const struct message WmHideChildInvisibleParentSeq[] = {
1047     { WM_SHOWWINDOW, sent|wparam, 0 },
1048     { 0 }
1049 };
1050 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1051 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1052     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1053     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1054     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1055     { 0 }
1056 };
1057 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1058 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1059     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1060     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1061     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1062     { 0 }
1063 };
1064 /* DestroyWindow for a visible child window */
1065 static const struct message WmDestroyChildSeq[] = {
1066     { HCBT_DESTROYWND, hook },
1067     { 0x0090, sent|optional },
1068     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1069     { WM_SHOWWINDOW, sent|wparam, 0 },
1070     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1071     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1072     { WM_ERASEBKGND, sent|parent|optional },
1073     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1074     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1075     { WM_KILLFOCUS, sent },
1076     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1077     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1078     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1079     { WM_SETFOCUS, sent|parent },
1080     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1081     { WM_DESTROY, sent },
1082     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1083     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1084     { WM_NCDESTROY, sent },
1085     { 0 }
1086 };
1087 /* DestroyWindow for a visible child window with invisible parent */
1088 static const struct message WmDestroyInvisibleChildSeq[] = {
1089     { HCBT_DESTROYWND, hook },
1090     { 0x0090, sent|optional },
1091     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1092     { WM_SHOWWINDOW, sent|wparam, 0 },
1093     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1094     { WM_DESTROY, sent },
1095     { WM_NCDESTROY, sent },
1096     { 0 }
1097 };
1098 /* Moving the mouse in nonclient area */
1099 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1100     { WM_NCHITTEST, sent },
1101     { WM_SETCURSOR, sent },
1102     { WM_NCMOUSEMOVE, posted },
1103     { 0 }
1104 };
1105 /* Moving the mouse in client area */
1106 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1107     { WM_NCHITTEST, sent },
1108     { WM_SETCURSOR, sent },
1109     { WM_MOUSEMOVE, posted },
1110     { 0 }
1111 };
1112 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1113 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1114     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1115     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1116     { WM_GETMINMAXINFO, sent|defwinproc },
1117     { WM_ENTERSIZEMOVE, sent|defwinproc },
1118     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1119     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1120     { WM_MOVE, sent|defwinproc },
1121     { WM_EXITSIZEMOVE, sent|defwinproc },
1122     { 0 }
1123 };
1124 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1125 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1126     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1127     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1128     { WM_GETMINMAXINFO, sent|defwinproc },
1129     { WM_ENTERSIZEMOVE, sent|defwinproc },
1130     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1131     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1132     { WM_GETMINMAXINFO, sent|defwinproc },
1133     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1134     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1135     { WM_GETTEXT, sent|defwinproc },
1136     { WM_ERASEBKGND, sent|defwinproc },
1137     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1138     { WM_MOVE, sent|defwinproc },
1139     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1140     { WM_EXITSIZEMOVE, sent|defwinproc },
1141     { 0 }
1142 };
1143 /* Resizing child window with MoveWindow (32) */
1144 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1145     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1146     { WM_NCCALCSIZE, sent|wparam, 1 },
1147     { WM_ERASEBKGND, sent|parent|optional },
1148     { WM_ERASEBKGND, sent|optional },
1149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1150     { WM_MOVE, sent|defwinproc },
1151     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1152     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1153     { 0 }
1154 };
1155 /* Clicking on inactive button */
1156 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1157     { WM_NCHITTEST, sent },
1158     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1159     { WM_MOUSEACTIVATE, sent },
1160     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1161     { WM_SETCURSOR, sent },
1162     { WM_SETCURSOR, sent|parent|defwinproc },
1163     { WM_LBUTTONDOWN, posted },
1164     { WM_KILLFOCUS, posted|parent },
1165     { WM_SETFOCUS, posted },
1166     { WM_CTLCOLORBTN, posted|parent },
1167     { BM_SETSTATE, posted },
1168     { WM_CTLCOLORBTN, posted|parent },
1169     { WM_LBUTTONUP, posted },
1170     { BM_SETSTATE, posted },
1171     { WM_CTLCOLORBTN, posted|parent },
1172     { WM_COMMAND, posted|parent },
1173     { 0 }
1174 };
1175 /* Reparenting a button (16/32) */
1176 /* The last child (button) reparented gets topmost for its new parent. */
1177 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1178     { WM_SHOWWINDOW, sent|wparam, 0 },
1179     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1180     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1181     { WM_ERASEBKGND, sent|parent },
1182     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1183     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1184     { WM_CHILDACTIVATE, sent },
1185     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1186     { WM_MOVE, sent|defwinproc },
1187     { WM_SHOWWINDOW, sent|wparam, 1 },
1188     { 0 }
1189 };
1190 /* Creation of a custom dialog (32) */
1191 static const struct message WmCreateCustomDialogSeq[] = {
1192     { HCBT_CREATEWND, hook },
1193     { WM_GETMINMAXINFO, sent },
1194     { WM_NCCREATE, sent },
1195     { WM_NCCALCSIZE, sent|wparam, 0 },
1196     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1197     { WM_CREATE, sent },
1198     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1199     { WM_NOTIFYFORMAT, sent|optional },
1200     { WM_QUERYUISTATE, sent|optional },
1201     { WM_WINDOWPOSCHANGING, sent|optional },
1202     { WM_GETMINMAXINFO, sent|optional },
1203     { WM_NCCALCSIZE, sent|optional },
1204     { WM_WINDOWPOSCHANGED, sent|optional },
1205     { WM_SHOWWINDOW, sent|wparam, 1 },
1206     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1207     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1208     { HCBT_ACTIVATE, hook },
1209     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1210
1211
1212     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1213
1214     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1215
1216     { WM_NCACTIVATE, sent|wparam, 1 },
1217     { WM_GETTEXT, sent|optional|defwinproc },
1218     { WM_GETTEXT, sent|optional|defwinproc },
1219     { WM_GETTEXT, sent|optional|defwinproc },
1220     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1221     { WM_ACTIVATE, sent|wparam, 1 },
1222     { WM_GETTEXT, sent|optional },
1223     { WM_KILLFOCUS, sent|parent },
1224     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1225     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1226     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1227     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1228     { WM_SETFOCUS, sent },
1229     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1230     { WM_NCPAINT, sent|wparam, 1 },
1231     { WM_GETTEXT, sent|optional|defwinproc },
1232     { WM_GETTEXT, sent|optional|defwinproc },
1233     { WM_ERASEBKGND, sent },
1234     { WM_CTLCOLORDLG, sent|defwinproc },
1235     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1236     { WM_GETTEXT, sent|optional },
1237     { WM_GETTEXT, sent|optional },
1238     { WM_NCCALCSIZE, sent|optional },
1239     { WM_NCPAINT, sent|optional },
1240     { WM_GETTEXT, sent|optional|defwinproc },
1241     { WM_GETTEXT, sent|optional|defwinproc },
1242     { WM_ERASEBKGND, sent|optional },
1243     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1244     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1245     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1246     { WM_MOVE, sent },
1247     { 0 }
1248 };
1249 /* Calling EndDialog for a custom dialog (32) */
1250 static const struct message WmEndCustomDialogSeq[] = {
1251     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1252     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1253     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1254     { WM_GETTEXT, sent|optional },
1255     { HCBT_ACTIVATE, hook },
1256     { WM_NCACTIVATE, sent|wparam, 0 },
1257     { WM_GETTEXT, sent|optional|defwinproc },
1258     { WM_GETTEXT, sent|optional|defwinproc },
1259     { WM_ACTIVATE, sent|wparam, 0 },
1260     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1261     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1262     { HCBT_SETFOCUS, hook },
1263     { WM_KILLFOCUS, sent },
1264     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1265     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1266     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1267     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1268     { WM_SETFOCUS, sent|parent|defwinproc },
1269     { 0 }
1270 };
1271 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1272 static const struct message WmShowCustomDialogSeq[] = {
1273     { WM_SHOWWINDOW, sent|wparam, 1 },
1274     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1275     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1276     { HCBT_ACTIVATE, hook },
1277     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1278
1279     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1280
1281     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1282     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1283     { WM_NCACTIVATE, sent|wparam, 1 },
1284     { WM_ACTIVATE, sent|wparam, 1 },
1285     { WM_GETTEXT, sent|optional },
1286
1287     { WM_KILLFOCUS, sent|parent },
1288     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1289     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1290     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1291     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1292     { WM_SETFOCUS, sent },
1293     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1294     { WM_NCPAINT, sent|wparam, 1 },
1295     { WM_ERASEBKGND, sent },
1296     { WM_CTLCOLORDLG, sent|defwinproc },
1297     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1298     { 0 }
1299 };
1300 /* Creation and destruction of a modal dialog (32) */
1301 static const struct message WmModalDialogSeq[] = {
1302     { WM_CANCELMODE, sent|parent },
1303     { HCBT_SETFOCUS, hook },
1304     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1305     { WM_KILLFOCUS, sent|parent },
1306     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1307     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1308     { WM_ENABLE, sent|parent|wparam, 0 },
1309     { HCBT_CREATEWND, hook },
1310     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1311     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1312     { WM_SETFONT, sent },
1313     { WM_INITDIALOG, sent },
1314     { WM_CHANGEUISTATE, sent|optional },
1315     { WM_UPDATEUISTATE, sent|optional },
1316     { WM_SHOWWINDOW, sent },
1317     { HCBT_ACTIVATE, hook },
1318     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1319     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1320     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1321     { WM_NCACTIVATE, sent|wparam, 1 },
1322     { WM_GETTEXT, sent|optional },
1323     { WM_ACTIVATE, sent|wparam, 1 },
1324     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1325     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1326     { WM_NCPAINT, sent },
1327     { WM_GETTEXT, sent|optional },
1328     { WM_ERASEBKGND, sent },
1329     { WM_CTLCOLORDLG, sent },
1330     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1331     { WM_GETTEXT, sent|optional },
1332     { WM_NCCALCSIZE, sent|optional },
1333     { WM_NCPAINT, sent|optional },
1334     { WM_GETTEXT, sent|optional },
1335     { WM_ERASEBKGND, sent|optional },
1336     { WM_CTLCOLORDLG, sent|optional },
1337     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1338     { WM_PAINT, sent|optional },
1339     { WM_CTLCOLORBTN, sent },
1340     { WM_ENTERIDLE, sent|parent|optional },
1341     { WM_ENTERIDLE, sent|parent|optional },
1342     { WM_ENTERIDLE, sent|parent|optional },
1343     { WM_ENTERIDLE, sent|parent|optional },
1344     { WM_ENTERIDLE, sent|parent|optional },
1345     { WM_ENTERIDLE, sent|parent|optional },
1346     { WM_ENTERIDLE, sent|parent|optional },
1347     { WM_ENTERIDLE, sent|parent|optional },
1348     { WM_ENTERIDLE, sent|parent|optional },
1349     { WM_ENTERIDLE, sent|parent|optional },
1350     { WM_ENTERIDLE, sent|parent|optional },
1351     { WM_ENTERIDLE, sent|parent|optional },
1352     { WM_ENTERIDLE, sent|parent|optional },
1353     { WM_ENTERIDLE, sent|parent|optional },
1354     { WM_ENTERIDLE, sent|parent|optional },
1355     { WM_ENTERIDLE, sent|parent|optional },
1356     { WM_ENTERIDLE, sent|parent|optional },
1357     { WM_ENTERIDLE, sent|parent|optional },
1358     { WM_ENTERIDLE, sent|parent|optional },
1359     { WM_ENTERIDLE, sent|parent|optional },
1360     { WM_TIMER, sent },
1361     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1362     { WM_ENABLE, sent|parent|wparam, 1 },
1363     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1364     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1365     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1366     { WM_GETTEXT, sent|optional },
1367     { HCBT_ACTIVATE, hook },
1368     { WM_NCACTIVATE, sent|wparam, 0 },
1369     { WM_GETTEXT, sent|optional },
1370     { WM_ACTIVATE, sent|wparam, 0 },
1371     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1372     { WM_WINDOWPOSCHANGING, sent|optional },
1373     { WM_WINDOWPOSCHANGED, sent|optional },
1374     { HCBT_SETFOCUS, hook },
1375     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1376     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1377     { WM_SETFOCUS, sent|parent|defwinproc },
1378     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1379     { HCBT_DESTROYWND, hook },
1380     { 0x0090, sent|optional },
1381     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1382     { WM_DESTROY, sent },
1383     { WM_NCDESTROY, sent },
1384     { 0 }
1385 };
1386 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1387 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1388     /* (inside dialog proc, handling WM_INITDIALOG) */
1389     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1390     { WM_NCCALCSIZE, sent },
1391     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1392     { WM_GETTEXT, sent|defwinproc },
1393     { WM_ACTIVATE, sent|parent|wparam, 0 },
1394     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1395     { WM_WINDOWPOSCHANGING, sent|parent },
1396     { WM_NCACTIVATE, sent|wparam, 1 },
1397     { WM_ACTIVATE, sent|wparam, 1 },
1398     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1399     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1400     /* (setting focus) */
1401     { WM_SHOWWINDOW, sent|wparam, 1 },
1402     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1403     { WM_NCPAINT, sent },
1404     { WM_GETTEXT, sent|defwinproc },
1405     { WM_ERASEBKGND, sent },
1406     { WM_CTLCOLORDLG, sent|defwinproc },
1407     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1408     { WM_PAINT, sent },
1409     /* (bunch of WM_CTLCOLOR* for each control) */
1410     { WM_PAINT, sent|parent },
1411     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1412     { WM_SETCURSOR, sent|parent },
1413     { 0 }
1414 };
1415 /* SetMenu for NonVisible windows with size change*/
1416 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1417     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1418     { WM_NCCALCSIZE, sent|wparam, 1 },
1419     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1420     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1421     { WM_MOVE, sent|defwinproc },
1422     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1423     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1424     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1425     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1426     { WM_GETTEXT, sent|optional },
1427     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1428     { 0 }
1429 };
1430 /* SetMenu for NonVisible windows with no size change */
1431 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1432     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1433     { WM_NCCALCSIZE, sent|wparam, 1 },
1434     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1435     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1436     { 0 }
1437 };
1438 /* SetMenu for Visible windows with size change */
1439 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1440     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1441     { WM_NCCALCSIZE, sent|wparam, 1 },
1442     { 0x0093, sent|defwinproc|optional },
1443     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1444     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1445     { 0x0093, sent|defwinproc|optional },
1446     { 0x0093, sent|defwinproc|optional },
1447     { 0x0091, sent|defwinproc|optional },
1448     { 0x0092, sent|defwinproc|optional },
1449     { WM_GETTEXT, sent|defwinproc|optional },
1450     { WM_ERASEBKGND, sent|optional },
1451     { WM_ACTIVATE, sent|optional },
1452     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1453     { WM_MOVE, sent|defwinproc },
1454     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1455     { 0x0093, sent|optional },
1456     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1457     { 0x0093, sent|defwinproc|optional },
1458     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1459     { 0x0093, sent|defwinproc|optional },
1460     { 0x0093, sent|defwinproc|optional },
1461     { 0x0091, sent|defwinproc|optional },
1462     { 0x0092, sent|defwinproc|optional },
1463     { WM_ERASEBKGND, sent|optional },
1464     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1465     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1466     { 0 }
1467 };
1468 /* SetMenu for Visible windows with no size change */
1469 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1470     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1471     { WM_NCCALCSIZE, sent|wparam, 1 },
1472     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1473     { WM_GETTEXT, sent|defwinproc|optional },
1474     { WM_ERASEBKGND, sent|optional },
1475     { WM_ACTIVATE, sent|optional },
1476     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1477     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1478     { 0 }
1479 };
1480 /* DrawMenuBar for a visible window */
1481 static const struct message WmDrawMenuBarSeq[] =
1482 {
1483     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1484     { WM_NCCALCSIZE, sent|wparam, 1 },
1485     { 0x0093, sent|defwinproc|optional },
1486     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1487     { 0x0093, sent|defwinproc|optional },
1488     { 0x0093, sent|defwinproc|optional },
1489     { 0x0091, sent|defwinproc|optional },
1490     { 0x0092, sent|defwinproc|optional },
1491     { WM_GETTEXT, sent|defwinproc|optional },
1492     { WM_ERASEBKGND, sent|optional },
1493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1494     { 0x0093, sent|optional },
1495     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1496     { 0 }
1497 };
1498
1499 static const struct message WmSetRedrawFalseSeq[] =
1500 {
1501     { WM_SETREDRAW, sent|wparam, 0 },
1502     { 0 }
1503 };
1504
1505 static const struct message WmSetRedrawTrueSeq[] =
1506 {
1507     { WM_SETREDRAW, sent|wparam, 1 },
1508     { 0 }
1509 };
1510
1511 static const struct message WmEnableWindowSeq_1[] =
1512 {
1513     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1514     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1515     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1516     { 0 }
1517 };
1518
1519 static const struct message WmEnableWindowSeq_2[] =
1520 {
1521     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1522     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1523     { 0 }
1524 };
1525
1526 static const struct message WmGetScrollRangeSeq[] =
1527 {
1528     { SBM_GETRANGE, sent },
1529     { 0 }
1530 };
1531 static const struct message WmGetScrollInfoSeq[] =
1532 {
1533     { SBM_GETSCROLLINFO, sent },
1534     { 0 }
1535 };
1536 static const struct message WmSetScrollRangeSeq[] =
1537 {
1538     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1539        sends SBM_SETSCROLLINFO.
1540      */
1541     { SBM_SETSCROLLINFO, sent },
1542     { 0 }
1543 };
1544 /* SetScrollRange for a window without a non-client area */
1545 static const struct message WmSetScrollRangeHSeq_empty[] =
1546 {
1547     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1548     { 0 }
1549 };
1550 static const struct message WmSetScrollRangeVSeq_empty[] =
1551 {
1552     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1553     { 0 }
1554 };
1555 static const struct message WmSetScrollRangeHVSeq[] =
1556 {
1557     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1558     { WM_NCCALCSIZE, sent|wparam, 1 },
1559     { WM_GETTEXT, sent|defwinproc|optional },
1560     { WM_ERASEBKGND, sent|optional },
1561     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1562     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1563     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1564     { 0 }
1565 };
1566 /* SetScrollRange for a window with a non-client area */
1567 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1568 {
1569     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1570     { WM_NCCALCSIZE, sent|wparam, 1 },
1571     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1572     { WM_NCPAINT, sent|optional },
1573     { WM_STYLECHANGING, sent|defwinproc|optional },
1574     { WM_STYLECHANGED, sent|defwinproc|optional },
1575     { WM_STYLECHANGING, sent|defwinproc|optional },
1576     { WM_STYLECHANGED, sent|defwinproc|optional },
1577     { WM_STYLECHANGING, sent|defwinproc|optional },
1578     { WM_STYLECHANGED, sent|defwinproc|optional },
1579     { WM_STYLECHANGING, sent|defwinproc|optional },
1580     { WM_STYLECHANGED, sent|defwinproc|optional },
1581     { WM_GETTEXT, sent|defwinproc|optional },
1582     { WM_GETTEXT, sent|defwinproc|optional },
1583     { WM_ERASEBKGND, sent|optional },
1584     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1585     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1586     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
1587     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1588     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1589     { WM_GETTEXT, sent|optional },
1590     { WM_GETTEXT, sent|optional },
1591     { WM_GETTEXT, sent|optional },
1592     { WM_GETTEXT, sent|optional },
1593     { 0 }
1594 };
1595 /* test if we receive the right sequence of messages */
1596 /* after calling ShowWindow( SW_SHOWNA) */
1597 static const struct message WmSHOWNAChildInvisParInvis[] = {
1598     { WM_SHOWWINDOW, sent|wparam, 1 },
1599     { 0 }
1600 };
1601 static const struct message WmSHOWNAChildVisParInvis[] = {
1602     { WM_SHOWWINDOW, sent|wparam, 1 },
1603     { 0 }
1604 };
1605 static const struct message WmSHOWNAChildVisParVis[] = {
1606     { WM_SHOWWINDOW, sent|wparam, 1 },
1607     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1608     { 0 }
1609 };
1610 static const struct message WmSHOWNAChildInvisParVis[] = {
1611     { WM_SHOWWINDOW, sent|wparam, 1 },
1612     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1613     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1614     { WM_ERASEBKGND, sent|optional },
1615     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1616     { 0 }
1617 };
1618 static const struct message WmSHOWNATopVisible[] = {
1619     { WM_SHOWWINDOW, sent|wparam, 1 },
1620     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1621     { WM_NCPAINT, sent|wparam|optional, 1 },
1622     { WM_GETTEXT, sent|defwinproc|optional },
1623     { WM_ERASEBKGND, sent|optional },
1624     { WM_WINDOWPOSCHANGED, sent|optional },
1625     { 0 }
1626 };
1627 static const struct message WmSHOWNATopInvisible[] = {
1628     { WM_NOTIFYFORMAT, sent|optional },
1629     { WM_QUERYUISTATE, sent|optional },
1630     { WM_WINDOWPOSCHANGING, sent|optional },
1631     { WM_GETMINMAXINFO, sent|optional },
1632     { WM_NCCALCSIZE, sent|optional },
1633     { WM_WINDOWPOSCHANGED, sent|optional },
1634     { WM_SHOWWINDOW, sent|wparam, 1 },
1635     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1636     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1637     { WM_NCPAINT, sent|wparam, 1 },
1638     { WM_GETTEXT, sent|defwinproc|optional },
1639     { WM_ERASEBKGND, sent|optional },
1640     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1641     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1642     { WM_NCPAINT, sent|wparam|optional, 1 },
1643     { WM_ERASEBKGND, sent|optional },
1644     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1645     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1646     { WM_MOVE, sent },
1647     { 0 }
1648 };
1649
1650 static int after_end_dialog, test_def_id;
1651 static int sequence_cnt, sequence_size;
1652 static struct recvd_message* sequence;
1653 static int log_all_parent_messages;
1654 static int paint_loop_done;
1655
1656 /* user32 functions */
1657 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1658 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1659 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1660 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1661 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1662 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1663 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1664 /* kernel32 functions */
1665 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1666
1667 static void init_procs(void)
1668 {
1669     HMODULE user32 = GetModuleHandleA("user32.dll");
1670     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1671
1672 #define GET_PROC(dll, func) \
1673     p ## func = (void*)GetProcAddress(dll, #func); \
1674     if(!p ## func) { \
1675       trace("GetProcAddress(%s) failed\n", #func); \
1676     }
1677
1678     GET_PROC(user32, GetAncestor)
1679     GET_PROC(user32, GetMenuInfo)
1680     GET_PROC(user32, NotifyWinEvent)
1681     GET_PROC(user32, SetMenuInfo)
1682     GET_PROC(user32, SetWinEventHook)
1683     GET_PROC(user32, TrackMouseEvent)
1684     GET_PROC(user32, UnhookWinEvent)
1685
1686     GET_PROC(kernel32, GetCPInfoExA)
1687
1688 #undef GET_PROC
1689 }
1690
1691 static const char *get_winpos_flags(UINT flags)
1692 {
1693     static char buffer[300];
1694
1695     buffer[0] = 0;
1696 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1697     DUMP( SWP_SHOWWINDOW );
1698     DUMP( SWP_HIDEWINDOW );
1699     DUMP( SWP_NOACTIVATE );
1700     DUMP( SWP_FRAMECHANGED );
1701     DUMP( SWP_NOCOPYBITS );
1702     DUMP( SWP_NOOWNERZORDER );
1703     DUMP( SWP_NOSENDCHANGING );
1704     DUMP( SWP_DEFERERASE );
1705     DUMP( SWP_ASYNCWINDOWPOS );
1706     DUMP( SWP_NOZORDER );
1707     DUMP( SWP_NOREDRAW );
1708     DUMP( SWP_NOSIZE );
1709     DUMP( SWP_NOMOVE );
1710     DUMP( SWP_NOCLIENTSIZE );
1711     DUMP( SWP_NOCLIENTMOVE );
1712     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1713     return buffer + 1;
1714 #undef DUMP
1715 }
1716
1717
1718 #define add_message(msg) add_message_(__LINE__,msg);
1719 static void add_message_(int line, const struct recvd_message *msg)
1720 {
1721     struct recvd_message *seq;
1722
1723     if (!sequence) 
1724     {
1725         sequence_size = 10;
1726         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1727     }
1728     if (sequence_cnt == sequence_size) 
1729     {
1730         sequence_size *= 2;
1731         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1732     }
1733     assert(sequence);
1734
1735     seq = &sequence[sequence_cnt];
1736     seq->hwnd = msg->hwnd;
1737     seq->message = msg->message;
1738     seq->flags = msg->flags;
1739     seq->wParam = msg->wParam;
1740     seq->lParam = msg->lParam;
1741     seq->line   = line;
1742     seq->descr  = msg->descr;
1743     seq->output[0] = 0;
1744
1745     if (msg->descr)
1746     {
1747         if (msg->flags & hook)
1748         {
1749             static const char * const CBT_code_name[10] =
1750             {
1751                 "HCBT_MOVESIZE",
1752                 "HCBT_MINMAX",
1753                 "HCBT_QS",
1754                 "HCBT_CREATEWND",
1755                 "HCBT_DESTROYWND",
1756                 "HCBT_ACTIVATE",
1757                 "HCBT_CLICKSKIPPED",
1758                 "HCBT_KEYSKIPPED",
1759                 "HCBT_SYSCOMMAND",
1760                 "HCBT_SETFOCUS"
1761             };
1762             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1763
1764             snprintf( seq->output, sizeof(seq->output), "%s: hook %d (%s) wp %08lx lp %08lx",
1765                       msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1766         }
1767         else if (msg->flags & winevent_hook)
1768         {
1769             snprintf( seq->output, sizeof(seq->output), "%s: winevent %p %08x %08lx %08lx",
1770                       msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1771         }
1772         else
1773         {
1774             switch (msg->message)
1775             {
1776             case WM_WINDOWPOSCHANGING:
1777             case WM_WINDOWPOSCHANGED:
1778             {
1779                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1780
1781                 snprintf( seq->output, sizeof(seq->output),
1782                           "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1783                           msg->descr, msg->hwnd,
1784                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1785                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1786                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1787                           get_winpos_flags(winpos->flags) );
1788
1789                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1790                  * in the high word for internal purposes
1791                  */
1792                 seq->wParam = winpos->flags & 0xffff;
1793                 /* We are not interested in the flags that don't match under XP and Win9x */
1794                 seq->wParam &= ~SWP_NOZORDER;
1795                 break;
1796             }
1797
1798             case WM_DRAWITEM:
1799             {
1800                 DRAW_ITEM_STRUCT di;
1801                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1802
1803                 snprintf( seq->output, sizeof(seq->output),
1804                           "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1805                           msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1806                           dis->itemID, dis->itemAction, dis->itemState);
1807
1808                 di.u.item.type = dis->CtlType;
1809                 di.u.item.ctl_id = dis->CtlID;
1810                 di.u.item.item_id = dis->itemID;
1811                 di.u.item.action = dis->itemAction;
1812                 di.u.item.state = dis->itemState;
1813
1814                 seq->lParam = di.u.lp;
1815                 break;
1816             }
1817             default:
1818                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1819                 snprintf( seq->output, sizeof(seq->output), "%s: %p %04x wp %08lx lp %08lx",
1820                           msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1821             }
1822         }
1823     }
1824
1825     sequence_cnt++;
1826 }
1827
1828 /* try to make sure pending X events have been processed before continuing */
1829 static void flush_events(void)
1830 {
1831     MSG msg;
1832     int diff = 200;
1833     int min_timeout = 100;
1834     DWORD time = GetTickCount() + diff;
1835
1836     while (diff > 0)
1837     {
1838         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1839         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1840         diff = time - GetTickCount();
1841     }
1842 }
1843
1844 static void flush_sequence(void)
1845 {
1846     HeapFree(GetProcessHeap(), 0, sequence);
1847     sequence = 0;
1848     sequence_cnt = sequence_size = 0;
1849 }
1850
1851 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1852 {
1853     const struct recvd_message *actual = sequence;
1854     unsigned int count = 0;
1855
1856     trace_(file, line)("Failed sequence %s:\n", context );
1857     while (expected->message && actual->message)
1858     {
1859         if (actual->output[0])
1860         {
1861             if (expected->flags & hook)
1862             {
1863                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1864                                     count, expected->message, actual->output );
1865             }
1866             else if (expected->flags & winevent_hook)
1867             {
1868                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1869                                     count, expected->message, actual->output );
1870             }
1871             else
1872             {
1873                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1874                                     count, expected->message, actual->output );
1875             }
1876         }
1877
1878         if (expected->message == actual->message)
1879         {
1880             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1881                 (expected->flags & optional))
1882             {
1883                 /* don't match messages if their defwinproc status differs */
1884                 expected++;
1885             }
1886             else
1887             {
1888                 expected++;
1889                 actual++;
1890             }
1891         }
1892         /* silently drop winevent messages if there is no support for them */
1893         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1894             expected++;
1895         else
1896         {
1897             expected++;
1898             actual++;
1899         }
1900         count++;
1901     }
1902
1903     /* optional trailing messages */
1904     while (expected->message && ((expected->flags & optional) ||
1905             ((expected->flags & winevent_hook) && !hEvent_hook)))
1906     {
1907         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1908         expected++;
1909         count++;
1910     }
1911
1912     if (expected->message)
1913         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1914     else if (actual->message && actual->output[0])
1915         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
1916 }
1917
1918 #define ok_sequence( exp, contx, todo) \
1919         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1920
1921
1922 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
1923                          const char *file, int line)
1924 {
1925     static const struct recvd_message end_of_sequence;
1926     const struct message *expected = expected_list;
1927     const struct recvd_message *actual;
1928     int failcount = 0, dump = 0;
1929     unsigned int count = 0;
1930
1931     add_message(&end_of_sequence);
1932
1933     actual = sequence;
1934
1935     while (expected->message && actual->message)
1936     {
1937         if (expected->message == actual->message)
1938         {
1939             if (expected->flags & wparam)
1940             {
1941                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
1942                 {
1943                     todo_wine {
1944                         failcount ++;
1945                         if (strcmp(winetest_platform, "wine")) dump++;
1946                         ok_( file, line) (FALSE,
1947                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1948                             context, count, expected->message, expected->wParam, actual->wParam);
1949                     }
1950                 }
1951                 else
1952                 {
1953                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
1954                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1955                                      context, count, expected->message, expected->wParam, actual->wParam);
1956                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
1957                 }
1958
1959             }
1960             if (expected->flags & lparam)
1961             {
1962                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
1963                 {
1964                     todo_wine {
1965                         failcount ++;
1966                         if (strcmp(winetest_platform, "wine")) dump++;
1967                         ok_( file, line) (FALSE,
1968                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1969                             context, count, expected->message, expected->lParam, actual->lParam);
1970                     }
1971                 }
1972                 else
1973                 {
1974                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
1975                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1976                                      context, count, expected->message, expected->lParam, actual->lParam);
1977                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
1978                 }
1979             }
1980             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1981                 (expected->flags & optional))
1982             {
1983                 /* don't match messages if their defwinproc status differs */
1984                 expected++;
1985                 count++;
1986                 continue;
1987             }
1988             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1989             {
1990                     todo_wine {
1991                         failcount ++;
1992                         if (strcmp(winetest_platform, "wine")) dump++;
1993                         ok_( file, line) (FALSE,
1994                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1995                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1996                     }
1997             }
1998             else
1999             {
2000                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2001                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2002                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2003                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2004             }
2005
2006             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2007                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2008                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2009             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2010
2011             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2012                 "%s: %u: the msg 0x%04x should have been %s\n",
2013                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2014             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2015
2016             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2017                 "%s: %u: the msg 0x%04x was expected in %s\n",
2018                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2019             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2020
2021             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2022                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2023                 context, count, expected->message);
2024             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2025
2026             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2027                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2028                 context, count, expected->message);
2029             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2030
2031             expected++;
2032             actual++;
2033         }
2034         /* silently drop hook messages if there is no support for them */
2035         else if ((expected->flags & optional) ||
2036                  ((expected->flags & hook) && !hCBT_hook) ||
2037                  ((expected->flags & winevent_hook) && !hEvent_hook))
2038             expected++;
2039         else if (todo)
2040         {
2041             failcount++;
2042             todo_wine {
2043                 if (strcmp(winetest_platform, "wine")) dump++;
2044                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2045                                   context, count, expected->message, actual->message);
2046             }
2047             goto done;
2048         }
2049         else
2050         {
2051             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2052                               context, count, expected->message, actual->message);
2053             dump++;
2054             expected++;
2055             actual++;
2056         }
2057         count++;
2058     }
2059
2060     /* skip all optional trailing messages */
2061     while (expected->message && ((expected->flags & optional) ||
2062                                  ((expected->flags & hook) && !hCBT_hook) ||
2063                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2064         expected++;
2065
2066     if (todo)
2067     {
2068         todo_wine {
2069             if (expected->message || actual->message) {
2070                 failcount++;
2071                 if (strcmp(winetest_platform, "wine")) dump++;
2072                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2073                                   context, count, expected->message, actual->message);
2074             }
2075         }
2076     }
2077     else
2078     {
2079         if (expected->message || actual->message)
2080         {
2081             dump++;
2082             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2083                               context, count, expected->message, actual->message);
2084         }
2085     }
2086     if( todo && !failcount) /* succeeded yet marked todo */
2087         todo_wine {
2088             if (!strcmp(winetest_platform, "wine")) dump++;
2089             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2090         }
2091
2092 done:
2093     if (dump) dump_sequence(expected_list, context, file, line);
2094     flush_sequence();
2095 }
2096
2097 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2098
2099 /******************************** MDI test **********************************/
2100
2101 /* CreateWindow for MDI frame window, initially visible */
2102 static const struct message WmCreateMDIframeSeq[] = {
2103     { HCBT_CREATEWND, hook },
2104     { WM_GETMINMAXINFO, sent },
2105     { WM_NCCREATE, sent },
2106     { WM_NCCALCSIZE, sent|wparam, 0 },
2107     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2108     { WM_CREATE, sent },
2109     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2110     { WM_NOTIFYFORMAT, sent|optional },
2111     { WM_QUERYUISTATE, sent|optional },
2112     { WM_WINDOWPOSCHANGING, sent|optional },
2113     { WM_GETMINMAXINFO, sent|optional },
2114     { WM_NCCALCSIZE, sent|optional },
2115     { WM_WINDOWPOSCHANGED, sent|optional },
2116     { WM_SHOWWINDOW, sent|wparam, 1 },
2117     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2118     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2119     { HCBT_ACTIVATE, hook },
2120     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2121     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2122     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2123     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2124     { WM_NCACTIVATE, sent|wparam, 1 },
2125     { WM_GETTEXT, sent|defwinproc|optional },
2126     { WM_ACTIVATE, sent|wparam, 1 },
2127     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2128     { HCBT_SETFOCUS, hook },
2129     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2130     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2131     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2132     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2133     /* Win9x adds SWP_NOZORDER below */
2134     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2135     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2136     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2137     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2138     { WM_MOVE, sent },
2139     { 0 }
2140 };
2141 /* DestroyWindow for MDI frame window, initially visible */
2142 static const struct message WmDestroyMDIframeSeq[] = {
2143     { HCBT_DESTROYWND, hook },
2144     { 0x0090, sent|optional },
2145     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2146     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2147     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2148     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2149     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2150     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2151     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2152     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2153     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2154     { WM_DESTROY, sent },
2155     { WM_NCDESTROY, sent },
2156     { 0 }
2157 };
2158 /* CreateWindow for MDI client window, initially visible */
2159 static const struct message WmCreateMDIclientSeq[] = {
2160     { HCBT_CREATEWND, hook },
2161     { WM_NCCREATE, sent },
2162     { WM_NCCALCSIZE, sent|wparam, 0 },
2163     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2164     { WM_CREATE, sent },
2165     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2166     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2167     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2168     { WM_MOVE, sent },
2169     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2170     { WM_SHOWWINDOW, sent|wparam, 1 },
2171     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2172     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2173     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2174     { 0 }
2175 };
2176 /* ShowWindow(SW_SHOW) for MDI client window */
2177 static const struct message WmShowMDIclientSeq[] = {
2178     { WM_SHOWWINDOW, sent|wparam, 1 },
2179     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2180     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2181     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2182     { 0 }
2183 };
2184 /* ShowWindow(SW_HIDE) for MDI client window */
2185 static const struct message WmHideMDIclientSeq[] = {
2186     { WM_SHOWWINDOW, sent|wparam, 0 },
2187     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2188     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2189     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2190     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2191     { 0 }
2192 };
2193 /* DestroyWindow for MDI client window, initially visible */
2194 static const struct message WmDestroyMDIclientSeq[] = {
2195     { HCBT_DESTROYWND, hook },
2196     { 0x0090, sent|optional },
2197     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2198     { WM_SHOWWINDOW, sent|wparam, 0 },
2199     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2200     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2201     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2202     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2203     { WM_DESTROY, sent },
2204     { WM_NCDESTROY, sent },
2205     { 0 }
2206 };
2207 /* CreateWindow for MDI child window, initially visible */
2208 static const struct message WmCreateMDIchildVisibleSeq[] = {
2209     { HCBT_CREATEWND, hook },
2210     { WM_NCCREATE, sent }, 
2211     { WM_NCCALCSIZE, sent|wparam, 0 },
2212     { WM_CREATE, sent },
2213     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2214     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2215     { WM_MOVE, sent },
2216     /* Win2k sends wparam set to
2217      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2218      * while Win9x doesn't bother to set child window id according to
2219      * CLIENTCREATESTRUCT.idFirstChild
2220      */
2221     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2222     { WM_SHOWWINDOW, sent|wparam, 1 },
2223     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2224     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2225     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2226     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2227     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2228     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2229     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2230
2231     /* Win9x: message sequence terminates here. */
2232
2233     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2234     { HCBT_SETFOCUS, hook }, /* in MDI client */
2235     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2236     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2237     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2238     { WM_SETFOCUS, sent }, /* in MDI client */
2239     { HCBT_SETFOCUS, hook },
2240     { WM_KILLFOCUS, sent }, /* in MDI client */
2241     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2242     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2243     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2244     { WM_SETFOCUS, sent|defwinproc },
2245     { WM_MDIACTIVATE, sent|defwinproc },
2246     { 0 }
2247 };
2248 /* CreateWindow for MDI child window with invisible parent */
2249 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2250     { HCBT_CREATEWND, hook },
2251     { WM_GETMINMAXINFO, sent },
2252     { WM_NCCREATE, sent }, 
2253     { WM_NCCALCSIZE, sent|wparam, 0 },
2254     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2255     { WM_CREATE, sent },
2256     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2257     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2258     { WM_MOVE, sent },
2259     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2260     { WM_SHOWWINDOW, sent|wparam, 1 },
2261     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2262     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2263     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2264     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2265
2266     /* Win9x: message sequence terminates here. */
2267
2268     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2269     { HCBT_SETFOCUS, hook }, /* in MDI client */
2270     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2271     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2272     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2273     { WM_SETFOCUS, sent }, /* in MDI client */
2274     { HCBT_SETFOCUS, hook },
2275     { WM_KILLFOCUS, sent }, /* in MDI client */
2276     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2277     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2278     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2279     { WM_SETFOCUS, sent|defwinproc },
2280     { WM_MDIACTIVATE, sent|defwinproc },
2281     { 0 }
2282 };
2283 /* DestroyWindow for MDI child window, initially visible */
2284 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2285     { HCBT_DESTROYWND, hook },
2286     /* Win2k sends wparam set to
2287      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2288      * while Win9x doesn't bother to set child window id according to
2289      * CLIENTCREATESTRUCT.idFirstChild
2290      */
2291     { 0x0090, sent|optional },
2292     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2293     { WM_SHOWWINDOW, sent|wparam, 0 },
2294     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2295     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2296     { WM_ERASEBKGND, sent|parent|optional },
2297     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2298
2299     /* { WM_DESTROY, sent }
2300      * Win9x: message sequence terminates here.
2301      */
2302
2303     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2304     { WM_KILLFOCUS, sent },
2305     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2306     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2307     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2308     { WM_SETFOCUS, sent }, /* in MDI client */
2309
2310     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2311     { WM_KILLFOCUS, sent }, /* in MDI client */
2312     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2313     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2314     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2315     { WM_SETFOCUS, sent }, /* in MDI client */
2316
2317     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2318
2319     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2320     { WM_KILLFOCUS, sent },
2321     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2322     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2323     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2324     { WM_SETFOCUS, sent }, /* in MDI client */
2325
2326     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2327     { WM_KILLFOCUS, sent }, /* in MDI client */
2328     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2329     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2330     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2331     { WM_SETFOCUS, sent }, /* in MDI client */
2332
2333     { WM_DESTROY, sent },
2334
2335     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2336     { WM_KILLFOCUS, sent },
2337     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2338     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2339     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2340     { WM_SETFOCUS, sent }, /* in MDI client */
2341
2342     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2343     { WM_KILLFOCUS, sent }, /* in MDI client */
2344     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2345     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2346     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2347     { WM_SETFOCUS, sent }, /* in MDI client */
2348
2349     { WM_NCDESTROY, sent },
2350     { 0 }
2351 };
2352 /* CreateWindow for MDI child window, initially invisible */
2353 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2354     { HCBT_CREATEWND, hook },
2355     { WM_NCCREATE, sent }, 
2356     { WM_NCCALCSIZE, sent|wparam, 0 },
2357     { WM_CREATE, sent },
2358     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2359     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2360     { WM_MOVE, sent },
2361     /* Win2k sends wparam set to
2362      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2363      * while Win9x doesn't bother to set child window id according to
2364      * CLIENTCREATESTRUCT.idFirstChild
2365      */
2366     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2367     { 0 }
2368 };
2369 /* DestroyWindow for MDI child window, initially invisible */
2370 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2371     { HCBT_DESTROYWND, hook },
2372     /* Win2k sends wparam set to
2373      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2374      * while Win9x doesn't bother to set child window id according to
2375      * CLIENTCREATESTRUCT.idFirstChild
2376      */
2377     { 0x0090, sent|optional },
2378     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2379     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2380     { WM_DESTROY, sent },
2381     { WM_NCDESTROY, sent },
2382     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2383     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2384     { 0 }
2385 };
2386 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2387 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2388     { HCBT_CREATEWND, hook },
2389     { WM_NCCREATE, sent }, 
2390     { WM_NCCALCSIZE, sent|wparam, 0 },
2391     { WM_CREATE, sent },
2392     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2393     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2394     { WM_MOVE, sent },
2395     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2396     { WM_GETMINMAXINFO, sent },
2397     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2398     { WM_NCCALCSIZE, sent|wparam, 1 },
2399     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2400     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2401      /* in MDI frame */
2402     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2403     { WM_NCCALCSIZE, sent|wparam, 1 },
2404     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2405     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2406     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2407     /* Win2k sends wparam set to
2408      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2409      * while Win9x doesn't bother to set child window id according to
2410      * CLIENTCREATESTRUCT.idFirstChild
2411      */
2412     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2413     { WM_SHOWWINDOW, sent|wparam, 1 },
2414     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2415     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2416     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2417     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2418     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2419     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2420     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2421
2422     /* Win9x: message sequence terminates here. */
2423
2424     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2425     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2426     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2427     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2428     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2429     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2430     { HCBT_SETFOCUS, hook|optional },
2431     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2432     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2433     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2434     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2435     { WM_SETFOCUS, sent|defwinproc|optional },
2436     { WM_MDIACTIVATE, sent|defwinproc|optional },
2437      /* in MDI frame */
2438     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2439     { WM_NCCALCSIZE, sent|wparam, 1 },
2440     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2441     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2442     { 0 }
2443 };
2444 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2445 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2446     /* restore the 1st MDI child */
2447     { WM_SETREDRAW, sent|wparam, 0 },
2448     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2449     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2450     { WM_NCCALCSIZE, sent|wparam, 1 },
2451     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2452     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2453     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2454      /* in MDI frame */
2455     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2456     { WM_NCCALCSIZE, sent|wparam, 1 },
2457     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2458     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2459     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2460     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2461     /* create the 2nd MDI child */
2462     { HCBT_CREATEWND, hook },
2463     { WM_NCCREATE, sent }, 
2464     { WM_NCCALCSIZE, sent|wparam, 0 },
2465     { WM_CREATE, sent },
2466     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2467     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2468     { WM_MOVE, sent },
2469     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2470     { WM_GETMINMAXINFO, sent },
2471     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2472     { WM_NCCALCSIZE, sent|wparam, 1 },
2473     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2474     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2475     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2476      /* in MDI frame */
2477     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2478     { WM_NCCALCSIZE, sent|wparam, 1 },
2479     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2480     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2481     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2482     /* Win2k sends wparam set to
2483      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2484      * while Win9x doesn't bother to set child window id according to
2485      * CLIENTCREATESTRUCT.idFirstChild
2486      */
2487     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2488     { WM_SHOWWINDOW, sent|wparam, 1 },
2489     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2490     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2491     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2492     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2493     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2494     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2495
2496     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2497     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2498
2499     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2500
2501     /* Win9x: message sequence terminates here. */
2502
2503     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2504     { HCBT_SETFOCUS, hook },
2505     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2506     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2507     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2508     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2509     { WM_SETFOCUS, sent }, /* in MDI client */
2510     { HCBT_SETFOCUS, hook },
2511     { WM_KILLFOCUS, sent }, /* in MDI client */
2512     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2513     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2514     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2515     { WM_SETFOCUS, sent|defwinproc },
2516
2517     { WM_MDIACTIVATE, sent|defwinproc },
2518      /* in MDI frame */
2519     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2520     { WM_NCCALCSIZE, sent|wparam, 1 },
2521     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2522     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2523     { 0 }
2524 };
2525 /* WM_MDICREATE MDI child window, initially visible and maximized */
2526 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2527     { WM_MDICREATE, sent },
2528     { HCBT_CREATEWND, hook },
2529     { WM_NCCREATE, sent }, 
2530     { WM_NCCALCSIZE, sent|wparam, 0 },
2531     { WM_CREATE, sent },
2532     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2533     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2534     { WM_MOVE, sent },
2535     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2536     { WM_GETMINMAXINFO, sent },
2537     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2538     { WM_NCCALCSIZE, sent|wparam, 1 },
2539     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2540     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2541
2542      /* in MDI frame */
2543     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2544     { WM_NCCALCSIZE, sent|wparam, 1 },
2545     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2546     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2547     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2548
2549     /* Win2k sends wparam set to
2550      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2551      * while Win9x doesn't bother to set child window id according to
2552      * CLIENTCREATESTRUCT.idFirstChild
2553      */
2554     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2555     { WM_SHOWWINDOW, sent|wparam, 1 },
2556     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2557
2558     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2559
2560     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2561     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2562     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2563
2564     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2565     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2566
2567     /* Win9x: message sequence terminates here. */
2568
2569     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2570     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2571     { HCBT_SETFOCUS, hook }, /* in MDI client */
2572     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2573     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2574     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2575     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2576     { HCBT_SETFOCUS, hook|optional },
2577     { WM_KILLFOCUS, sent }, /* in MDI client */
2578     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2579     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2580     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2581     { WM_SETFOCUS, sent|defwinproc },
2582
2583     { WM_MDIACTIVATE, sent|defwinproc },
2584
2585      /* in MDI child */
2586     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2587     { WM_NCCALCSIZE, sent|wparam, 1 },
2588     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2589     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2590
2591      /* in MDI frame */
2592     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2593     { WM_NCCALCSIZE, sent|wparam, 1 },
2594     { 0x0093, sent|defwinproc|optional },
2595     { 0x0093, sent|defwinproc|optional },
2596     { 0x0093, sent|defwinproc|optional },
2597     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2598     { WM_MOVE, sent|defwinproc },
2599     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2600
2601      /* in MDI client */
2602     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2603     { WM_NCCALCSIZE, sent|wparam, 1 },
2604     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2605     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2606
2607      /* in MDI child */
2608     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2609     { WM_NCCALCSIZE, sent|wparam, 1 },
2610     { 0x0093, sent|optional },
2611     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2612     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2613
2614     { 0x0093, sent|optional },
2615     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2616     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2617     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2618     { 0x0093, sent|defwinproc|optional },
2619     { 0x0093, sent|defwinproc|optional },
2620     { 0x0093, sent|defwinproc|optional },
2621     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2622     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2623
2624     { 0 }
2625 };
2626 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2627 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2628     { HCBT_CREATEWND, hook },
2629     { WM_GETMINMAXINFO, sent },
2630     { WM_NCCREATE, sent }, 
2631     { WM_NCCALCSIZE, sent|wparam, 0 },
2632     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2633     { WM_CREATE, sent },
2634     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2635     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2636     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2637     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2638     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2639     { WM_MOVE, sent },
2640     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2641     { WM_GETMINMAXINFO, sent },
2642     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2643     { WM_GETMINMAXINFO, sent|defwinproc },
2644     { WM_NCCALCSIZE, sent|wparam, 1 },
2645     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2646     { WM_MOVE, sent|defwinproc },
2647     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2648      /* in MDI frame */
2649     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2650     { WM_NCCALCSIZE, sent|wparam, 1 },
2651     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2652     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2653     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2654     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2655     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2656     /* Win2k sends wparam set to
2657      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2658      * while Win9x doesn't bother to set child window id according to
2659      * CLIENTCREATESTRUCT.idFirstChild
2660      */
2661     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2662     { 0 }
2663 };
2664 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2665 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2666     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2667     { HCBT_SYSCOMMAND, hook },
2668     { WM_CLOSE, sent|defwinproc },
2669     { WM_MDIDESTROY, sent }, /* in MDI client */
2670
2671     /* bring the 1st MDI child to top */
2672     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2673     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2674
2675     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2676
2677     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2678     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2679     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2680
2681     /* maximize the 1st MDI child */
2682     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2683     { WM_GETMINMAXINFO, sent|defwinproc },
2684     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2685     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2686     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2687     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2688     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2689
2690     /* restore the 2nd MDI child */
2691     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2692     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2693     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2694     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2695
2696     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2697
2698     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2699     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2700
2701     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2702
2703     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2704      /* in MDI frame */
2705     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2706     { WM_NCCALCSIZE, sent|wparam, 1 },
2707     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2708     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2709     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2710
2711     /* bring the 1st MDI child to top */
2712     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2713     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2714     { HCBT_SETFOCUS, hook },
2715     { WM_KILLFOCUS, sent|defwinproc },
2716     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2717     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2718     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2719     { WM_SETFOCUS, sent }, /* in MDI client */
2720     { HCBT_SETFOCUS, hook },
2721     { WM_KILLFOCUS, sent }, /* in MDI client */
2722     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2723     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2724     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2725     { WM_SETFOCUS, sent|defwinproc },
2726     { WM_MDIACTIVATE, sent|defwinproc },
2727     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2728
2729     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2730     { WM_SHOWWINDOW, sent|wparam, 1 },
2731     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2732     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2733     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2734     { WM_MDIREFRESHMENU, sent },
2735
2736     { HCBT_DESTROYWND, hook },
2737     /* Win2k sends wparam set to
2738      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2739      * while Win9x doesn't bother to set child window id according to
2740      * CLIENTCREATESTRUCT.idFirstChild
2741      */
2742     { 0x0090, sent|defwinproc|optional },
2743     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2744     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2745     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2746     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2747     { WM_ERASEBKGND, sent|parent|optional },
2748     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2749
2750     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2751     { WM_DESTROY, sent|defwinproc },
2752     { WM_NCDESTROY, sent|defwinproc },
2753     { 0 }
2754 };
2755 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2756 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2757     { WM_MDIDESTROY, sent }, /* in MDI client */
2758     { WM_SHOWWINDOW, sent|wparam, 0 },
2759     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2760     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2761     { WM_ERASEBKGND, sent|parent|optional },
2762     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2763
2764     { HCBT_SETFOCUS, hook },
2765     { WM_KILLFOCUS, sent },
2766     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2767     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2768     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2769     { WM_SETFOCUS, sent }, /* in MDI client */
2770     { HCBT_SETFOCUS, hook },
2771     { WM_KILLFOCUS, sent }, /* in MDI client */
2772     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2773     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2774     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2775     { WM_SETFOCUS, sent },
2776
2777      /* in MDI child */
2778     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2779     { WM_NCCALCSIZE, sent|wparam, 1 },
2780     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2781     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2782
2783      /* in MDI frame */
2784     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2785     { WM_NCCALCSIZE, sent|wparam, 1 },
2786     { 0x0093, sent|defwinproc|optional },
2787     { 0x0093, sent|defwinproc|optional },
2788     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2789     { WM_MOVE, sent|defwinproc },
2790     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2791
2792      /* in MDI client */
2793     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2794     { WM_NCCALCSIZE, sent|wparam, 1 },
2795     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2796     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2797
2798      /* in MDI child */
2799     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2800     { WM_NCCALCSIZE, sent|wparam, 1 },
2801     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2802     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2803
2804      /* in MDI child */
2805     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2806     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2807     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2808     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2809
2810      /* in MDI frame */
2811     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2812     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2813     { 0x0093, sent|defwinproc|optional },
2814     { 0x0093, sent|defwinproc|optional },
2815     { 0x0093, sent|defwinproc|optional },
2816     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2817     { WM_MOVE, sent|defwinproc },
2818     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2819
2820      /* in MDI client */
2821     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2822     { WM_NCCALCSIZE, sent|wparam, 1 },
2823     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2824     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2825
2826      /* in MDI child */
2827     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2828     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2829     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2830     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2831     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2832     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2833
2834     { 0x0093, sent|defwinproc|optional },
2835     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2836     { 0x0093, sent|defwinproc|optional },
2837     { 0x0093, sent|defwinproc|optional },
2838     { 0x0093, sent|defwinproc|optional },
2839     { 0x0093, sent|optional },
2840
2841     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2842     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2843     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2844     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2845     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2846
2847      /* in MDI frame */
2848     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2849     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2850     { 0x0093, sent|defwinproc|optional },
2851     { 0x0093, sent|defwinproc|optional },
2852     { 0x0093, sent|defwinproc|optional },
2853     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2854     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2855     { 0x0093, sent|optional },
2856
2857     { WM_NCACTIVATE, sent|wparam, 0 },
2858     { WM_MDIACTIVATE, sent },
2859
2860     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2861     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2862     { WM_NCCALCSIZE, sent|wparam, 1 },
2863
2864     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2865
2866     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2867     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2868     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2869
2870      /* in MDI child */
2871     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2872     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2873     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2874     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2875
2876      /* in MDI frame */
2877     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2878     { WM_NCCALCSIZE, sent|wparam, 1 },
2879     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2880     { WM_MOVE, sent|defwinproc },
2881     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2882
2883      /* in MDI client */
2884     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2885     { WM_NCCALCSIZE, sent|wparam, 1 },
2886     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2887     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2888     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2889     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2890     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2891     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2892     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2893
2894     { HCBT_SETFOCUS, hook },
2895     { WM_KILLFOCUS, sent },
2896     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2897     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2898     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2899     { WM_SETFOCUS, sent }, /* in MDI client */
2900
2901     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2902
2903     { HCBT_DESTROYWND, hook },
2904     /* Win2k sends wparam set to
2905      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2906      * while Win9x doesn't bother to set child window id according to
2907      * CLIENTCREATESTRUCT.idFirstChild
2908      */
2909     { 0x0090, sent|optional },
2910     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2911
2912     { WM_SHOWWINDOW, sent|wparam, 0 },
2913     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2914     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2915     { WM_ERASEBKGND, sent|parent|optional },
2916     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2917
2918     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2919     { WM_DESTROY, sent },
2920     { WM_NCDESTROY, sent },
2921     { 0 }
2922 };
2923 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2924 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2925     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2926     { WM_GETMINMAXINFO, sent },
2927     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2928     { WM_NCCALCSIZE, sent|wparam, 1 },
2929     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2930     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2931
2932     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2933     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
2934     { HCBT_SETFOCUS, hook|optional },
2935     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2936     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2937     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2938     { HCBT_SETFOCUS, hook|optional },
2939     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2940     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2941     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2942     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2943     { WM_SETFOCUS, sent|optional|defwinproc },
2944     { WM_MDIACTIVATE, sent|optional|defwinproc },
2945     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2946     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2947      /* in MDI frame */
2948     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2949     { WM_NCCALCSIZE, sent|wparam, 1 },
2950     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2951     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2952     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2953     { 0 }
2954 };
2955 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2956 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2957     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2958     { WM_GETMINMAXINFO, sent },
2959     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2960     { WM_GETMINMAXINFO, sent|defwinproc },
2961     { WM_NCCALCSIZE, sent|wparam, 1 },
2962     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2963     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2964
2965     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2966     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2967     { HCBT_SETFOCUS, hook|optional },
2968     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2969     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2970     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2971     { HCBT_SETFOCUS, hook|optional },
2972     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2973     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2974     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2975     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2976     { WM_SETFOCUS, sent|defwinproc|optional },
2977     { WM_MDIACTIVATE, sent|defwinproc|optional },
2978     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2979     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2980     { 0 }
2981 };
2982 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2983 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2984     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2985     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2986     { WM_GETMINMAXINFO, sent },
2987     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2988     { WM_GETMINMAXINFO, sent|defwinproc },
2989     { WM_NCCALCSIZE, sent|wparam, 1 },
2990     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2991     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2992     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
2993     { WM_MOVE, sent|defwinproc },
2994     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2995
2996     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2997     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2998     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2999     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3000     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3001     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3002      /* in MDI frame */
3003     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3004     { WM_NCCALCSIZE, sent|wparam, 1 },
3005     { 0x0093, sent|defwinproc|optional },
3006     { 0x0094, sent|defwinproc|optional },
3007     { 0x0094, sent|defwinproc|optional },
3008     { 0x0094, sent|defwinproc|optional },
3009     { 0x0094, sent|defwinproc|optional },
3010     { 0x0093, sent|defwinproc|optional },
3011     { 0x0093, sent|defwinproc|optional },
3012     { 0x0091, sent|defwinproc|optional },
3013     { 0x0092, sent|defwinproc|optional },
3014     { 0x0092, sent|defwinproc|optional },
3015     { 0x0092, sent|defwinproc|optional },
3016     { 0x0092, sent|defwinproc|optional },
3017     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3018     { WM_MOVE, sent|defwinproc },
3019     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3020     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3021      /* in MDI client */
3022     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3023     { WM_NCCALCSIZE, sent|wparam, 1 },
3024     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3025     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3026      /* in MDI child */
3027     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3028     { WM_GETMINMAXINFO, sent|defwinproc },
3029     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3030     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3031     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3032     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3033     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3034     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3035     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3036     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3037      /* in MDI frame */
3038     { 0x0093, sent|optional },
3039     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3040     { 0x0093, sent|defwinproc|optional },
3041     { 0x0093, sent|defwinproc|optional },
3042     { 0x0093, sent|defwinproc|optional },
3043     { 0x0091, sent|defwinproc|optional },
3044     { 0x0092, sent|defwinproc|optional },
3045     { 0x0092, sent|defwinproc|optional },
3046     { 0x0092, sent|defwinproc|optional },
3047     { 0x0092, sent|defwinproc|optional },
3048     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3049     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3050     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3051     { 0 }
3052 };
3053 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3054 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3055     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3056     { WM_GETMINMAXINFO, sent },
3057     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3058     { WM_NCCALCSIZE, sent|wparam, 1 },
3059     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3060     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3061     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3062      /* in MDI frame */
3063     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3064     { WM_NCCALCSIZE, sent|wparam, 1 },
3065     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3066     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3067     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3068     { 0 }
3069 };
3070 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3071 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3072     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3073     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3074     { WM_NCCALCSIZE, sent|wparam, 1 },
3075     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3076     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3077     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3078      /* in MDI frame */
3079     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3080     { WM_NCCALCSIZE, sent|wparam, 1 },
3081     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3082     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3083     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3084     { 0 }
3085 };
3086 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3087 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3088     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3089     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3090     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3091     { WM_NCCALCSIZE, sent|wparam, 1 },
3092     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3093     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3094     { WM_MOVE, sent|defwinproc },
3095     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3096     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3097     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3098     { HCBT_SETFOCUS, hook },
3099     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3100     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3101     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3102     { WM_SETFOCUS, sent },
3103     { 0 }
3104 };
3105 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3106 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3107     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3108     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3109     { WM_NCCALCSIZE, sent|wparam, 1 },
3110     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3111     { WM_MOVE, sent|defwinproc },
3112     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
3113     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3114     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3115     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3116     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3117     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3118     { 0 }
3119 };
3120 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3121 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3122     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3123     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3124     { WM_NCCALCSIZE, sent|wparam, 1 },
3125     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3126     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3127     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3128     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3129      /* in MDI frame */
3130     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3131     { WM_NCCALCSIZE, sent|wparam, 1 },
3132     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3133     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3134     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3135     { 0 }
3136 };
3137
3138 static HWND mdi_client;
3139 static WNDPROC old_mdi_client_proc;
3140
3141 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3142 {
3143     struct recvd_message msg;
3144
3145     /* do not log painting messages */
3146     if (message != WM_PAINT &&
3147         message != WM_NCPAINT &&
3148         message != WM_SYNCPAINT &&
3149         message != WM_ERASEBKGND &&
3150         message != WM_NCHITTEST &&
3151         message != WM_GETTEXT &&
3152         message != WM_MDIGETACTIVE &&
3153         message != WM_GETICON &&
3154         message != WM_GETOBJECT &&
3155         message != WM_DEVICECHANGE)
3156     {
3157         msg.hwnd = hwnd;
3158         msg.message = message;
3159         msg.flags = sent|wparam|lparam;
3160         msg.wParam = wParam;
3161         msg.lParam = lParam;
3162         msg.descr = "mdi client";
3163         add_message(&msg);
3164     }
3165
3166     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3167 }
3168
3169 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3170 {
3171     static long defwndproc_counter = 0;
3172     LRESULT ret;
3173     struct recvd_message msg;
3174
3175     /* do not log painting messages */
3176     if (message != WM_PAINT &&
3177         message != WM_NCPAINT &&
3178         message != WM_SYNCPAINT &&
3179         message != WM_ERASEBKGND &&
3180         message != WM_NCHITTEST &&
3181         message != WM_GETTEXT &&
3182         message != WM_GETICON &&
3183         message != WM_GETOBJECT &&
3184         message != WM_DEVICECHANGE)
3185     {
3186         switch (message)
3187         {
3188             case WM_MDIACTIVATE:
3189             {
3190                 HWND active, client = GetParent(hwnd);
3191
3192                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3193
3194                 if (hwnd == (HWND)lParam) /* if we are being activated */
3195                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3196                 else
3197                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3198                 break;
3199             }
3200         }
3201
3202         msg.hwnd = hwnd;
3203         msg.message = message;
3204         msg.flags = sent|wparam|lparam;
3205         if (defwndproc_counter) msg.flags |= defwinproc;
3206         msg.wParam = wParam;
3207         msg.lParam = lParam;
3208         msg.descr = "mdi child";
3209         add_message(&msg);
3210     }
3211
3212     defwndproc_counter++;
3213     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3214     defwndproc_counter--;
3215
3216     return ret;
3217 }
3218
3219 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3220 {
3221     static long defwndproc_counter = 0;
3222     LRESULT ret;
3223     struct recvd_message msg;
3224
3225     /* do not log painting messages */
3226     if (message != WM_PAINT &&
3227         message != WM_NCPAINT &&
3228         message != WM_SYNCPAINT &&
3229         message != WM_ERASEBKGND &&
3230         message != WM_NCHITTEST &&
3231         message != WM_GETTEXT &&
3232         message != WM_GETICON &&
3233         message != WM_GETOBJECT &&
3234         message != WM_DEVICECHANGE)
3235     {
3236         msg.hwnd = hwnd;
3237         msg.message = message;
3238         msg.flags = sent|wparam|lparam;
3239         if (defwndproc_counter) msg.flags |= defwinproc;
3240         msg.wParam = wParam;
3241         msg.lParam = lParam;
3242         msg.descr = "mdi frame";
3243         add_message(&msg);
3244     }
3245
3246     defwndproc_counter++;
3247     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3248     defwndproc_counter--;
3249
3250     return ret;
3251 }
3252
3253 static BOOL mdi_RegisterWindowClasses(void)
3254 {
3255     WNDCLASSA cls;
3256
3257     cls.style = 0;
3258     cls.lpfnWndProc = mdi_frame_wnd_proc;
3259     cls.cbClsExtra = 0;
3260     cls.cbWndExtra = 0;
3261     cls.hInstance = GetModuleHandleA(0);
3262     cls.hIcon = 0;
3263     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3264     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3265     cls.lpszMenuName = NULL;
3266     cls.lpszClassName = "MDI_frame_class";
3267     if (!RegisterClassA(&cls)) return FALSE;
3268
3269     cls.lpfnWndProc = mdi_child_wnd_proc;
3270     cls.lpszClassName = "MDI_child_class";
3271     if (!RegisterClassA(&cls)) return FALSE;
3272
3273     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3274     old_mdi_client_proc = cls.lpfnWndProc;
3275     cls.hInstance = GetModuleHandleA(0);
3276     cls.lpfnWndProc = mdi_client_hook_proc;
3277     cls.lpszClassName = "MDI_client_class";
3278     if (!RegisterClassA(&cls)) assert(0);
3279
3280     return TRUE;
3281 }
3282
3283 static void test_mdi_messages(void)
3284 {
3285     MDICREATESTRUCTA mdi_cs;
3286     CLIENTCREATESTRUCT client_cs;
3287     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3288     BOOL zoomed;
3289     HMENU hMenu = CreateMenu();
3290
3291     assert(mdi_RegisterWindowClasses());
3292
3293     flush_sequence();
3294
3295     trace("creating MDI frame window\n");
3296     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3297                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3298                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3299                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3300                                 GetDesktopWindow(), hMenu,
3301                                 GetModuleHandleA(0), NULL);
3302     assert(mdi_frame);
3303     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3304
3305     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3306     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3307
3308     trace("creating MDI client window\n");
3309     client_cs.hWindowMenu = 0;
3310     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3311     mdi_client = CreateWindowExA(0, "MDI_client_class",
3312                                  NULL,
3313                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3314                                  0, 0, 0, 0,
3315                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3316     assert(mdi_client);
3317     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3318
3319     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3320     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3321
3322     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3323     ok(!active_child, "wrong active MDI child %p\n", active_child);
3324     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3325
3326     SetFocus(0);
3327     flush_sequence();
3328
3329     trace("creating invisible MDI child window\n");
3330     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3331                                 WS_CHILD,
3332                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3333                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3334     assert(mdi_child);
3335
3336     flush_sequence();
3337     ShowWindow(mdi_child, SW_SHOWNORMAL);
3338     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3339
3340     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3341     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3342
3343     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3344     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3345
3346     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3347     ok(!active_child, "wrong active MDI child %p\n", active_child);
3348     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3349
3350     ShowWindow(mdi_child, SW_HIDE);
3351     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3352     flush_sequence();
3353
3354     ShowWindow(mdi_child, SW_SHOW);
3355     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3356
3357     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3358     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3359
3360     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3361     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3362
3363     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3364     ok(!active_child, "wrong active MDI child %p\n", active_child);
3365     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3366
3367     DestroyWindow(mdi_child);
3368     flush_sequence();
3369
3370     trace("creating visible MDI child window\n");
3371     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3372                                 WS_CHILD | WS_VISIBLE,
3373                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3374                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3375     assert(mdi_child);
3376     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3377
3378     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3379     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3380
3381     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3382     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3383
3384     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3385     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3386     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3387     flush_sequence();
3388
3389     DestroyWindow(mdi_child);
3390     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3391
3392     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3393     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3394
3395     /* Win2k: MDI client still returns a just destroyed child as active
3396      * Win9x: MDI client returns 0
3397      */
3398     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3399     ok(active_child == mdi_child || /* win2k */
3400        !active_child, /* win9x */
3401        "wrong active MDI child %p\n", active_child);
3402     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3403
3404     flush_sequence();
3405
3406     trace("creating invisible MDI child window\n");
3407     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3408                                 WS_CHILD,
3409                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3410                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3411     assert(mdi_child2);
3412     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3413
3414     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3415     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3416
3417     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3418     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3419
3420     /* Win2k: MDI client still returns a just destroyed child as active
3421      * Win9x: MDI client returns mdi_child2
3422      */
3423     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3424     ok(active_child == mdi_child || /* win2k */
3425        active_child == mdi_child2, /* win9x */
3426        "wrong active MDI child %p\n", active_child);
3427     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3428     flush_sequence();
3429
3430     ShowWindow(mdi_child2, SW_MAXIMIZE);
3431     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3432
3433     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3434     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3435
3436     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3437     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3438     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3439     flush_sequence();
3440
3441     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3442     ok(GetFocus() == mdi_child2 || /* win2k */
3443        GetFocus() == 0, /* win9x */
3444        "wrong focus window %p\n", GetFocus());
3445
3446     SetFocus(0);
3447     flush_sequence();
3448
3449     ShowWindow(mdi_child2, SW_HIDE);
3450     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3451
3452     ShowWindow(mdi_child2, SW_RESTORE);
3453     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3454     flush_sequence();
3455
3456     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3457     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3458
3459     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3460     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3461     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3462     flush_sequence();
3463
3464     SetFocus(0);
3465     flush_sequence();
3466
3467     ShowWindow(mdi_child2, SW_HIDE);
3468     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3469
3470     ShowWindow(mdi_child2, SW_SHOW);
3471     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3472
3473     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3474     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3475
3476     ShowWindow(mdi_child2, SW_MAXIMIZE);
3477     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3478
3479     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3480     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3481
3482     ShowWindow(mdi_child2, SW_RESTORE);
3483     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3484
3485     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3486     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3487
3488     ShowWindow(mdi_child2, SW_MINIMIZE);
3489     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3490
3491     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3492     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3493
3494     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3495     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3496     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3497     flush_sequence();
3498
3499     ShowWindow(mdi_child2, SW_RESTORE);
3500     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3501
3502     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3503     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3504
3505     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3506     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3507     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3508     flush_sequence();
3509
3510     SetFocus(0);
3511     flush_sequence();
3512
3513     ShowWindow(mdi_child2, SW_HIDE);
3514     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3515
3516     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3517     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3518
3519     DestroyWindow(mdi_child2);
3520     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3521
3522     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3523     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3524
3525     /* test for maximized MDI children */
3526     trace("creating maximized visible MDI child window 1\n");
3527     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3528                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3529                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3530                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3531     assert(mdi_child);
3532     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3533     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3534
3535     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3536     ok(GetFocus() == mdi_child || /* win2k */
3537        GetFocus() == 0, /* win9x */
3538        "wrong focus window %p\n", GetFocus());
3539
3540     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3541     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3542     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3543     flush_sequence();
3544
3545     trace("creating maximized visible MDI child window 2\n");
3546     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3547                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3548                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3549                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3550     assert(mdi_child2);
3551     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3552     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3553     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3554
3555     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3556     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3557
3558     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3559     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3560     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3561     flush_sequence();
3562
3563     trace("destroying maximized visible MDI child window 2\n");
3564     DestroyWindow(mdi_child2);
3565     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3566
3567     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3568
3569     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3570     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3571
3572     /* Win2k: MDI client still returns a just destroyed child as active
3573      * Win9x: MDI client returns 0
3574      */
3575     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3576     ok(active_child == mdi_child2 || /* win2k */
3577        !active_child, /* win9x */
3578        "wrong active MDI child %p\n", active_child);
3579     flush_sequence();
3580
3581     ShowWindow(mdi_child, SW_MAXIMIZE);
3582     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3583     flush_sequence();
3584
3585     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3586     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3587
3588     trace("re-creating maximized visible MDI child window 2\n");
3589     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3590                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3591                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3592                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3593     assert(mdi_child2);
3594     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3595     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3596     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3597
3598     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3599     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3600
3601     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3602     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3603     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3604     flush_sequence();
3605
3606     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3607     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3608     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3609
3610     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3611     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3612     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3613
3614     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3615     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3616     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3617     flush_sequence();
3618
3619     DestroyWindow(mdi_child);
3620     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3621
3622     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3623     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3624
3625     /* Win2k: MDI client still returns a just destroyed child as active
3626      * Win9x: MDI client returns 0
3627      */
3628     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3629     ok(active_child == mdi_child || /* win2k */
3630        !active_child, /* win9x */
3631        "wrong active MDI child %p\n", active_child);
3632     flush_sequence();
3633
3634     trace("creating maximized invisible MDI child window\n");
3635     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3636                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3637                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3638                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3639     assert(mdi_child2);
3640     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3641     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3642     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3643     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3644
3645     /* Win2k: MDI client still returns a just destroyed child as active
3646      * Win9x: MDI client returns 0
3647      */
3648     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3649     ok(active_child == mdi_child || /* win2k */
3650        !active_child, /* win9x */
3651        "wrong active MDI child %p\n", active_child);
3652     flush_sequence();
3653
3654     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3655     ShowWindow(mdi_child2, SW_MAXIMIZE);
3656     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3657     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3658     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3659     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3660
3661     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3662     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3663     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3664     flush_sequence();
3665
3666     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3667     flush_sequence();
3668
3669     /* end of test for maximized MDI children */
3670     SetFocus(0);
3671     flush_sequence();
3672     trace("creating maximized visible MDI child window 1(Switch test)\n");
3673     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3674                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3675                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3676                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3677     assert(mdi_child);
3678     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3679     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3680
3681     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3682     ok(GetFocus() == mdi_child || /* win2k */
3683        GetFocus() == 0, /* win9x */
3684        "wrong focus window %p(Switch test)\n", GetFocus());
3685
3686     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3687     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3688     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3689     flush_sequence();
3690
3691     trace("creating maximized visible MDI child window 2(Switch test)\n");
3692     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3693                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3694                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3695                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3696     assert(mdi_child2);
3697     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3698
3699     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3700     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3701
3702     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3703     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3704
3705     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3706     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3707     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3708     flush_sequence();
3709
3710     trace("Switch child window.\n");
3711     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3712     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3713     trace("end of test for switch maximized MDI children\n");
3714     flush_sequence();
3715
3716     /* Prepare for switching test of not maximized MDI children  */
3717     ShowWindow( mdi_child, SW_NORMAL );
3718     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3719     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3720     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3721     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3722     flush_sequence();
3723
3724     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3725     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3726     trace("end of test for switch not maximized MDI children\n");
3727     flush_sequence();
3728
3729     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3730     flush_sequence();
3731
3732     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3733     flush_sequence();
3734
3735     SetFocus(0);
3736     flush_sequence();
3737     /* end of tests for switch maximized/not maximized MDI children */
3738
3739     mdi_cs.szClass = "MDI_child_Class";
3740     mdi_cs.szTitle = "MDI child";
3741     mdi_cs.hOwner = GetModuleHandleA(0);
3742     mdi_cs.x = 0;
3743     mdi_cs.y = 0;
3744     mdi_cs.cx = CW_USEDEFAULT;
3745     mdi_cs.cy = CW_USEDEFAULT;
3746     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3747     mdi_cs.lParam = 0;
3748     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3749     ok(mdi_child != 0, "MDI child creation failed\n");
3750     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3751
3752     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3753
3754     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3755     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3756
3757     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3758     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3759     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3760
3761     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3762     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3763     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3764     flush_sequence();
3765
3766     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3767     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3768
3769     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3770     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3771     ok(!active_child, "wrong active MDI child %p\n", active_child);
3772
3773     SetFocus(0);
3774     flush_sequence();
3775
3776     DestroyWindow(mdi_client);
3777     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3778
3779     /* test maximization of MDI child with invisible parent */
3780     client_cs.hWindowMenu = 0;
3781     mdi_client = CreateWindow("MDI_client_class",
3782                                  NULL,
3783                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3784                                  0, 0, 660, 430,
3785                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3786     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3787
3788     ShowWindow(mdi_client, SW_HIDE);
3789     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3790
3791     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3792                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3793                                 0, 0, 650, 440,
3794                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3795     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3796
3797     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3798     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3799     zoomed = IsZoomed(mdi_child);
3800     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3801     
3802     ShowWindow(mdi_client, SW_SHOW);
3803     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3804
3805     DestroyWindow(mdi_child);
3806     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3807
3808     /* end of test for maximization of MDI child with invisible parent */
3809
3810     DestroyWindow(mdi_client);
3811     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3812
3813     DestroyWindow(mdi_frame);
3814     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3815 }
3816 /************************* End of MDI test **********************************/
3817
3818 static void test_WM_SETREDRAW(HWND hwnd)
3819 {
3820     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3821
3822     flush_events();
3823     flush_sequence();
3824
3825     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3826     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3827
3828     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3829     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3830
3831     flush_sequence();
3832     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3833     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3834
3835     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3836     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3837
3838     /* restore original WS_VISIBLE state */
3839     SetWindowLongA(hwnd, GWL_STYLE, style);
3840
3841     flush_events();
3842     flush_sequence();
3843 }
3844
3845 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3846 {
3847     struct recvd_message msg;
3848
3849     switch (message)
3850     {
3851         /* ignore */
3852         case WM_GETICON:
3853         case WM_GETOBJECT:
3854         case WM_MOUSEMOVE:
3855         case WM_NCMOUSEMOVE:
3856         case WM_NCMOUSELEAVE:
3857         case WM_SETCURSOR:
3858         case WM_DEVICECHANGE:
3859             return 0;
3860         case WM_NCHITTEST:
3861             return HTCLIENT;
3862     }
3863
3864     msg.hwnd = hwnd;
3865     msg.message = message;
3866     msg.flags = sent|wparam|lparam;
3867     msg.wParam = wParam;
3868     msg.lParam = lParam;
3869     msg.descr = "dialog";
3870     add_message(&msg);
3871
3872     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3873     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3874     return 0;
3875 }
3876
3877 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3878 {
3879     DWORD style, exstyle;
3880     INT xmin, xmax;
3881     BOOL ret;
3882
3883     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3884     style = GetWindowLongA(hwnd, GWL_STYLE);
3885     /* do not be confused by WS_DLGFRAME set */
3886     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3887
3888     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3889     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3890
3891     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3892     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3893     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3894         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3895     else
3896         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3897
3898     style = GetWindowLongA(hwnd, GWL_STYLE);
3899     if (set) ok(style & set, "style %08x should be set\n", set);
3900     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3901
3902     /* a subsequent call should do nothing */
3903     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3904     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3905     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3906
3907     xmin = 0xdeadbeef;
3908     xmax = 0xdeadbeef;
3909     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3910     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3911     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3912     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3913     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3914     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3915 }
3916
3917 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3918 {
3919     DWORD style, exstyle;
3920     SCROLLINFO si;
3921     BOOL ret;
3922
3923     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3924     style = GetWindowLongA(hwnd, GWL_STYLE);
3925     /* do not be confused by WS_DLGFRAME set */
3926     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3927
3928     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3929     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3930
3931     si.cbSize = sizeof(si);
3932     si.fMask = SIF_RANGE;
3933     si.nMin = min;
3934     si.nMax = max;
3935     SetScrollInfo(hwnd, ctl, &si, TRUE);
3936     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3937         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3938     else
3939         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3940
3941     style = GetWindowLongA(hwnd, GWL_STYLE);
3942     if (set) ok(style & set, "style %08x should be set\n", set);
3943     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3944
3945     /* a subsequent call should do nothing */
3946     SetScrollInfo(hwnd, ctl, &si, TRUE);
3947     if (style & WS_HSCROLL)
3948         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3949     else if (style & WS_VSCROLL)
3950         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3951     else
3952         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3953
3954     si.fMask = SIF_PAGE;
3955     si.nPage = 5;
3956     SetScrollInfo(hwnd, ctl, &si, FALSE);
3957     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3958
3959     si.fMask = SIF_POS;
3960     si.nPos = max - 1;
3961     SetScrollInfo(hwnd, ctl, &si, FALSE);
3962     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3963
3964     si.fMask = SIF_RANGE;
3965     si.nMin = 0xdeadbeef;
3966     si.nMax = 0xdeadbeef;
3967     ret = GetScrollInfo(hwnd, ctl, &si);
3968     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3969     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3970     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3971     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3972 }
3973
3974 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3975 static void test_scroll_messages(HWND hwnd)
3976 {
3977     SCROLLINFO si;
3978     INT min, max;
3979     BOOL ret;
3980
3981     flush_events();
3982     flush_sequence();
3983
3984     min = 0xdeadbeef;
3985     max = 0xdeadbeef;
3986     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3987     ok( ret, "GetScrollRange error %d\n", GetLastError());
3988     if (sequence->message != WmGetScrollRangeSeq[0].message)
3989         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3990     /* values of min and max are undefined */
3991     flush_sequence();
3992
3993     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3994     ok( ret, "SetScrollRange error %d\n", GetLastError());
3995     if (sequence->message != WmSetScrollRangeSeq[0].message)
3996         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3997     flush_sequence();
3998
3999     min = 0xdeadbeef;
4000     max = 0xdeadbeef;
4001     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4002     ok( ret, "GetScrollRange error %d\n", GetLastError());
4003     if (sequence->message != WmGetScrollRangeSeq[0].message)
4004         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4005     /* values of min and max are undefined */
4006     flush_sequence();
4007
4008     si.cbSize = sizeof(si);
4009     si.fMask = SIF_RANGE;
4010     si.nMin = 20;
4011     si.nMax = 160;
4012     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4013     if (sequence->message != WmSetScrollRangeSeq[0].message)
4014         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4015     flush_sequence();
4016
4017     si.fMask = SIF_PAGE;
4018     si.nPage = 10;
4019     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4020     if (sequence->message != WmSetScrollRangeSeq[0].message)
4021         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4022     flush_sequence();
4023
4024     si.fMask = SIF_POS;
4025     si.nPos = 20;
4026     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4027     if (sequence->message != WmSetScrollRangeSeq[0].message)
4028         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4029     flush_sequence();
4030
4031     si.fMask = SIF_RANGE;
4032     si.nMin = 0xdeadbeef;
4033     si.nMax = 0xdeadbeef;
4034     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4035     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4036     if (sequence->message != WmGetScrollInfoSeq[0].message)
4037         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4038     /* values of min and max are undefined */
4039     flush_sequence();
4040
4041     /* set WS_HSCROLL */
4042     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4043     /* clear WS_HSCROLL */
4044     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4045
4046     /* set WS_HSCROLL */
4047     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4048     /* clear WS_HSCROLL */
4049     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4050
4051     /* set WS_VSCROLL */
4052     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4053     /* clear WS_VSCROLL */
4054     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4055
4056     /* set WS_VSCROLL */
4057     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4058     /* clear WS_VSCROLL */
4059     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4060 }
4061
4062 static void test_showwindow(void)
4063 {
4064     HWND hwnd, hchild;
4065     RECT rc;
4066
4067     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4068                            100, 100, 200, 200, 0, 0, 0, NULL);
4069     ok (hwnd != 0, "Failed to create overlapped window\n");
4070     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4071                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4072     ok (hchild != 0, "Failed to create child\n");
4073     flush_sequence();
4074
4075     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4076     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4077     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4078     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
4079
4080     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4081     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4082     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4083     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4084     /* back to invisible */
4085     ShowWindow(hchild, SW_HIDE);
4086     ShowWindow(hwnd, SW_HIDE);
4087     flush_sequence();
4088     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4089     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4090     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4091     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4092     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4093     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4094     flush_sequence();
4095     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4096     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4097     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4098     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4099     ShowWindow( hwnd, SW_SHOW);
4100     flush_sequence();
4101     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4102     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4103     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4104
4105     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4106     ShowWindow( hchild, SW_HIDE);
4107     flush_sequence();
4108     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4109     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4110     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4111
4112     SetCapture(hchild);
4113     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4114     DestroyWindow(hchild);
4115     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4116
4117     DestroyWindow(hwnd);
4118     flush_sequence();
4119
4120     /* Popup windows */
4121     /* Test 1:
4122      * 1. Create invisible maximized popup window.
4123      * 2. Move and resize it.
4124      * 3. Show it maximized.
4125      */
4126     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4127     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4128                            100, 100, 200, 200, 0, 0, 0, NULL);
4129     ok (hwnd != 0, "Failed to create popup window\n");
4130     ok(IsZoomed(hwnd), "window should be maximized\n");
4131     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4132
4133     GetWindowRect(hwnd, &rc);
4134     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4135         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4136         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4137         rc.left, rc.top, rc.right, rc.bottom);
4138     /* Reset window's size & position */
4139     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4140     ok(IsZoomed(hwnd), "window should be maximized\n");
4141     flush_sequence();
4142
4143     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4144     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4145     ok(IsZoomed(hwnd), "window should be maximized\n");
4146     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4147
4148     GetWindowRect(hwnd, &rc);
4149     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4150         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4151         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4152         rc.left, rc.top, rc.right, rc.bottom);
4153     DestroyWindow(hwnd);
4154     flush_sequence();
4155
4156     /* Test 2:
4157      * 1. Create invisible maximized popup window.
4158      * 2. Show it maximized.
4159      */
4160     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4161     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4162                            100, 100, 200, 200, 0, 0, 0, NULL);
4163     ok (hwnd != 0, "Failed to create popup window\n");
4164     ok(IsZoomed(hwnd), "window should be maximized\n");
4165     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4166
4167     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4168     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4169     ok(IsZoomed(hwnd), "window should be maximized\n");
4170     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4171     DestroyWindow(hwnd);
4172     flush_sequence();
4173
4174     /* Test 3:
4175      * 1. Create visible maximized popup window.
4176      */
4177     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4178     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4179                            100, 100, 200, 200, 0, 0, 0, NULL);
4180     ok (hwnd != 0, "Failed to create popup window\n");
4181     ok(IsZoomed(hwnd), "window should be maximized\n");
4182     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4183     DestroyWindow(hwnd);
4184     flush_sequence();
4185
4186     /* Test 4:
4187      * 1. Create visible popup window.
4188      * 2. Maximize it.
4189      */
4190     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4191     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4192                            100, 100, 200, 200, 0, 0, 0, NULL);
4193     ok (hwnd != 0, "Failed to create popup window\n");
4194     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4195     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4196
4197     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4198     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4199     ok(IsZoomed(hwnd), "window should be maximized\n");
4200     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4201     DestroyWindow(hwnd);
4202     flush_sequence();
4203 }
4204
4205 static void test_sys_menu(void)
4206 {
4207     HWND hwnd;
4208     HMENU hmenu;
4209     UINT state;
4210
4211     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4212                            100, 100, 200, 200, 0, 0, 0, NULL);
4213     ok (hwnd != 0, "Failed to create overlapped window\n");
4214
4215     flush_sequence();
4216
4217     /* test existing window without CS_NOCLOSE style */
4218     hmenu = GetSystemMenu(hwnd, FALSE);
4219     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4220
4221     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4222     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4223     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4224
4225     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4226     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4227
4228     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4229     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4230     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4231
4232     EnableMenuItem(hmenu, SC_CLOSE, 0);
4233     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4234
4235     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4236     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4237     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4238
4239     /* test whether removing WS_SYSMENU destroys a system menu */
4240     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4241     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4242     flush_sequence();
4243     hmenu = GetSystemMenu(hwnd, FALSE);
4244     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4245
4246     DestroyWindow(hwnd);
4247
4248     /* test new window with CS_NOCLOSE style */
4249     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4250                            100, 100, 200, 200, 0, 0, 0, NULL);
4251     ok (hwnd != 0, "Failed to create overlapped window\n");
4252
4253     hmenu = GetSystemMenu(hwnd, FALSE);
4254     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4255
4256     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4257     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4258
4259     DestroyWindow(hwnd);
4260
4261     /* test new window without WS_SYSMENU style */
4262     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4263                            100, 100, 200, 200, 0, 0, 0, NULL);
4264     ok(hwnd != 0, "Failed to create overlapped window\n");
4265
4266     hmenu = GetSystemMenu(hwnd, FALSE);
4267     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4268
4269     DestroyWindow(hwnd);
4270 }
4271
4272 /* For shown WS_OVERLAPPEDWINDOW */
4273 static const struct message WmSetIcon_1[] = {
4274     { WM_SETICON, sent },
4275     { 0x00AE, sent|defwinproc|optional }, /* XP */
4276     { WM_GETTEXT, sent|defwinproc|optional },
4277     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4278     { 0 }
4279 };
4280
4281 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4282 static const struct message WmSetIcon_2[] = {
4283     { WM_SETICON, sent },
4284     { 0 }
4285 };
4286
4287 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4288 static const struct message WmInitEndSession[] = {
4289     { 0x003B, sent },
4290     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4291     { 0 }
4292 };
4293
4294 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4295 static const struct message WmInitEndSession_2[] = {
4296     { 0x003B, sent },
4297     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4298     { 0 }
4299 };
4300
4301 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4302 static const struct message WmInitEndSession_3[] = {
4303     { 0x003B, sent },
4304     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4305     { 0 }
4306 };
4307
4308 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4309 static const struct message WmInitEndSession_4[] = {
4310     { 0x003B, sent },
4311     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4312     { 0 }
4313 };
4314
4315 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4316 static const struct message WmInitEndSession_5[] = {
4317     { 0x003B, sent },
4318     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4319     { 0 }
4320 };
4321
4322 static const struct message WmOptionalPaint[] = {
4323     { WM_PAINT, sent|optional },
4324     { WM_NCPAINT, sent|beginpaint|optional },
4325     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4326     { WM_ERASEBKGND, sent|beginpaint|optional },
4327     { 0 }
4328 };
4329
4330 static const struct message WmZOrder[] = {
4331     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4332     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4333     { HCBT_ACTIVATE, hook },
4334     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4335     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4336     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4337     { WM_GETTEXT, sent|optional },
4338     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4339     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4340     { WM_NCACTIVATE, sent|wparam|lparam, 1, 0 },
4341     { WM_GETTEXT, sent|defwinproc|optional },
4342     { WM_GETTEXT, sent|defwinproc|optional },
4343     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4344     { HCBT_SETFOCUS, hook },
4345     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4346     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4347     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4348     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4349     { WM_GETTEXT, sent|optional },
4350     { WM_NCCALCSIZE, sent|optional },
4351     { 0 }
4352 };
4353
4354 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4355 {
4356     DWORD ret;
4357     MSG msg;
4358
4359     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4360     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4361
4362     PostMessageA(hwnd, WM_USER, 0, 0);
4363
4364     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4365     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4366
4367     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4368     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4369
4370     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4371     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4372
4373     PostMessageA(hwnd, WM_USER, 0, 0);
4374
4375     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4376     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4377
4378     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4379     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4380
4381     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4382     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4383     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4384
4385     PostMessageA(hwnd, WM_USER, 0, 0);
4386
4387     /* new incoming message causes it to become signaled again */
4388     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4389     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4390
4391     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4392     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4393     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4394     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4395 }
4396
4397 /* test if we receive the right sequence of messages */
4398 static void test_messages(void)
4399 {
4400     HWND hwnd, hparent, hchild;
4401     HWND hchild2, hbutton;
4402     HMENU hmenu;
4403     MSG msg;
4404     LRESULT res;
4405
4406     flush_sequence();
4407
4408     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4409                            100, 100, 200, 200, 0, 0, 0, NULL);
4410     ok (hwnd != 0, "Failed to create overlapped window\n");
4411     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4412
4413     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4414     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4415     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4416
4417     /* test WM_SETREDRAW on a not visible top level window */
4418     test_WM_SETREDRAW(hwnd);
4419
4420     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4421     flush_events();
4422     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4423     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4424
4425     ok(GetActiveWindow() == hwnd, "window should be active\n");
4426     ok(GetFocus() == hwnd, "window should have input focus\n");
4427     ShowWindow(hwnd, SW_HIDE);
4428     flush_events();
4429     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4430
4431     ShowWindow(hwnd, SW_SHOW);
4432     flush_events();
4433     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4434
4435     ShowWindow(hwnd, SW_HIDE);
4436     flush_events();
4437     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4438
4439     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4440     flush_events();
4441     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4442     flush_sequence();
4443
4444     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4445     {
4446         ShowWindow(hwnd, SW_RESTORE);
4447         flush_events();
4448         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4449         flush_sequence();
4450     }
4451
4452     ShowWindow(hwnd, SW_MINIMIZE);
4453     flush_events();
4454     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4455     flush_sequence();
4456
4457     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4458     {
4459         ShowWindow(hwnd, SW_RESTORE);
4460         flush_events();
4461         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4462         flush_sequence();
4463     }
4464
4465     ShowWindow(hwnd, SW_SHOW);
4466     flush_events();
4467     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4468
4469     ok(GetActiveWindow() == hwnd, "window should be active\n");
4470     ok(GetFocus() == hwnd, "window should have input focus\n");
4471     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4472     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4473     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4474     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4475
4476     /* test WM_SETREDRAW on a visible top level window */
4477     ShowWindow(hwnd, SW_SHOW);
4478     flush_events();
4479     test_WM_SETREDRAW(hwnd);
4480
4481     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4482     test_scroll_messages(hwnd);
4483
4484     /* test resizing and moving */
4485     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4486     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4487     flush_events();
4488     flush_sequence();
4489     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4490     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4491     flush_events();
4492     flush_sequence();
4493     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4494     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4495     flush_events();
4496     flush_sequence();
4497
4498     /* popups don't get WM_GETMINMAXINFO */
4499     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4500     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4501     flush_sequence();
4502     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4503     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4504
4505     DestroyWindow(hwnd);
4506     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4507
4508     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4509                               100, 100, 200, 200, 0, 0, 0, NULL);
4510     ok (hparent != 0, "Failed to create parent window\n");
4511     flush_sequence();
4512
4513     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4514                              0, 0, 10, 10, hparent, 0, 0, NULL);
4515     ok (hchild != 0, "Failed to create child window\n");
4516     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4517     DestroyWindow(hchild);
4518     flush_sequence();
4519
4520     /* visible child window with a caption */
4521     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4522                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4523                              0, 0, 10, 10, hparent, 0, 0, NULL);
4524     ok (hchild != 0, "Failed to create child window\n");
4525     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4526
4527     trace("testing scroll APIs on a visible child window %p\n", hchild);
4528     test_scroll_messages(hchild);
4529
4530     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4531     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4532
4533     DestroyWindow(hchild);
4534     flush_sequence();
4535
4536     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4537                              0, 0, 10, 10, hparent, 0, 0, NULL);
4538     ok (hchild != 0, "Failed to create child window\n");
4539     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4540     
4541     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4542                                100, 100, 50, 50, hparent, 0, 0, NULL);
4543     ok (hchild2 != 0, "Failed to create child2 window\n");
4544     flush_sequence();
4545
4546     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4547                               0, 100, 50, 50, hchild, 0, 0, NULL);
4548     ok (hbutton != 0, "Failed to create button window\n");
4549
4550     /* test WM_SETREDRAW on a not visible child window */
4551     test_WM_SETREDRAW(hchild);
4552
4553     ShowWindow(hchild, SW_SHOW);
4554     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4555
4556     /* check parent messages too */
4557     log_all_parent_messages++;
4558     ShowWindow(hchild, SW_HIDE);
4559     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4560     log_all_parent_messages--;
4561
4562     ShowWindow(hchild, SW_SHOW);
4563     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4564
4565     ShowWindow(hchild, SW_HIDE);
4566     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4567
4568     ShowWindow(hchild, SW_SHOW);
4569     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4570
4571     /* test WM_SETREDRAW on a visible child window */
4572     test_WM_SETREDRAW(hchild);
4573
4574     log_all_parent_messages++;
4575     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4576     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4577     log_all_parent_messages--;
4578
4579     ShowWindow(hchild, SW_HIDE);
4580     flush_sequence();
4581     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4582     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4583
4584     ShowWindow(hchild, SW_HIDE);
4585     flush_sequence();
4586     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4587     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4588
4589     /* DestroyWindow sequence below expects that a child has focus */
4590     SetFocus(hchild);
4591     flush_sequence();
4592
4593     DestroyWindow(hchild);
4594     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4595     DestroyWindow(hchild2);
4596     DestroyWindow(hbutton);
4597
4598     flush_sequence();
4599     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4600                              0, 0, 100, 100, hparent, 0, 0, NULL);
4601     ok (hchild != 0, "Failed to create child popup window\n");
4602     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4603     DestroyWindow(hchild);
4604
4605     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4606     flush_sequence();
4607     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4608                              0, 0, 100, 100, hparent, 0, 0, NULL);
4609     ok (hchild != 0, "Failed to create popup window\n");
4610     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4611     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4612     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4613     flush_sequence();
4614     ShowWindow(hchild, SW_SHOW);
4615     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4616     flush_sequence();
4617     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4618     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4619     flush_sequence();
4620     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4621     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4622     DestroyWindow(hchild);
4623
4624     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4625      * changes nothing in message sequences.
4626      */
4627     flush_sequence();
4628     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4629                              0, 0, 100, 100, hparent, 0, 0, NULL);
4630     ok (hchild != 0, "Failed to create popup window\n");
4631     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4632     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4633     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4634     flush_sequence();
4635     ShowWindow(hchild, SW_SHOW);
4636     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4637     flush_sequence();
4638     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4639     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4640     DestroyWindow(hchild);
4641
4642     flush_sequence();
4643     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4644                            0, 0, 100, 100, hparent, 0, 0, NULL);
4645     ok(hwnd != 0, "Failed to create custom dialog window\n");
4646     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4647
4648     /*
4649     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4650     test_scroll_messages(hwnd);
4651     */
4652
4653     flush_sequence();
4654
4655     test_def_id = 1;
4656     SendMessage(hwnd, WM_NULL, 0, 0);
4657
4658     flush_sequence();
4659     after_end_dialog = 1;
4660     EndDialog( hwnd, 0 );
4661     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4662
4663     DestroyWindow(hwnd);
4664     after_end_dialog = 0;
4665     test_def_id = 0;
4666
4667     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4668                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4669     ok(hwnd != 0, "Failed to create custom dialog window\n");
4670     flush_sequence();
4671     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4672     ShowWindow(hwnd, SW_SHOW);
4673     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4674     DestroyWindow(hwnd);
4675
4676     flush_sequence();
4677     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4678     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4679
4680     DestroyWindow(hparent);
4681     flush_sequence();
4682
4683     /* Message sequence for SetMenu */
4684     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4685     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4686
4687     hmenu = CreateMenu();
4688     ok (hmenu != 0, "Failed to create menu\n");
4689     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4690     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4691                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4692     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4693     ok (SetMenu(hwnd, 0), "SetMenu\n");
4694     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4695     ok (SetMenu(hwnd, 0), "SetMenu\n");
4696     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4697     ShowWindow(hwnd, SW_SHOW);
4698     UpdateWindow( hwnd );
4699     flush_events();
4700     flush_sequence();
4701     ok (SetMenu(hwnd, 0), "SetMenu\n");
4702     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4703     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4704     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4705
4706     UpdateWindow( hwnd );
4707     flush_events();
4708     flush_sequence();
4709     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4710     flush_events();
4711     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4712
4713     DestroyWindow(hwnd);
4714     flush_sequence();
4715
4716     /* Message sequence for EnableWindow */
4717     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4718                               100, 100, 200, 200, 0, 0, 0, NULL);
4719     ok (hparent != 0, "Failed to create parent window\n");
4720     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4721                              0, 0, 10, 10, hparent, 0, 0, NULL);
4722     ok (hchild != 0, "Failed to create child window\n");
4723
4724     SetFocus(hchild);
4725     flush_events();
4726     flush_sequence();
4727
4728     EnableWindow(hparent, FALSE);
4729     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4730
4731     EnableWindow(hparent, TRUE);
4732     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4733
4734     flush_events();
4735     flush_sequence();
4736
4737     test_MsgWaitForMultipleObjects(hparent);
4738
4739     /* the following test causes an exception in user.exe under win9x */
4740     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4741     {
4742         DestroyWindow(hparent);
4743         flush_sequence();
4744         return;
4745     }
4746     PostMessageW( hparent, WM_USER+1, 0, 0 );
4747     /* PeekMessage(NULL) fails, but still removes the message */
4748     SetLastError(0xdeadbeef);
4749     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4750     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4751         GetLastError() == 0xdeadbeef, /* NT4 */
4752         "last error is %d\n", GetLastError() );
4753     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4754     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4755
4756     DestroyWindow(hchild);
4757     DestroyWindow(hparent);
4758     flush_sequence();
4759
4760     /* Message sequences for WM_SETICON */
4761     trace("testing WM_SETICON\n");
4762     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4763                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4764                            NULL, NULL, 0);
4765     ShowWindow(hwnd, SW_SHOW);
4766     UpdateWindow(hwnd);
4767     flush_events();
4768     flush_sequence();
4769     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4770     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4771
4772     ShowWindow(hwnd, SW_HIDE);
4773     flush_events();
4774     flush_sequence();
4775     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4776     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4777     DestroyWindow(hwnd);
4778     flush_sequence();
4779
4780     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4781                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4782                            NULL, NULL, 0);
4783     ShowWindow(hwnd, SW_SHOW);
4784     UpdateWindow(hwnd);
4785     flush_events();
4786     flush_sequence();
4787     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4788     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4789
4790     ShowWindow(hwnd, SW_HIDE);
4791     flush_events();
4792     flush_sequence();
4793     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4794     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4795
4796     flush_sequence();
4797     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4798     if (!res)
4799     {
4800         todo_wine win_skip( "Message 0x3b not supported\n" );
4801         goto done;
4802     }
4803     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4804     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4805     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4806     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4807     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4808     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4809     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4810     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4811
4812     flush_sequence();
4813     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4814     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4815     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4816     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4817     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4818     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4819
4820     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4821     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4822     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4823
4824     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4825     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4826     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4827
4828 done:
4829     DestroyWindow(hwnd);
4830     flush_sequence();
4831 }
4832
4833 static void test_setwindowpos(void)
4834 {
4835     HWND hwnd;
4836     RECT rc;
4837     LRESULT res;
4838     const INT winX = 100;
4839     const INT winY = 100;
4840     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4841
4842     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4843                            0, 0, winX, winY, 0,
4844                            NULL, NULL, 0);
4845
4846     GetWindowRect(hwnd, &rc);
4847     expect(sysX, rc.right);
4848     expect(winY, rc.bottom);
4849
4850     flush_events();
4851     flush_sequence();
4852     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4853     ok_sequence(WmZOrder, "Z-Order", TRUE);
4854     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4855
4856     GetWindowRect(hwnd, &rc);
4857     expect(sysX, rc.right);
4858     expect(winY, rc.bottom);
4859     DestroyWindow(hwnd);
4860 }
4861
4862 static void invisible_parent_tests(void)
4863 {
4864     HWND hparent, hchild;
4865
4866     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4867                               100, 100, 200, 200, 0, 0, 0, NULL);
4868     ok (hparent != 0, "Failed to create parent window\n");
4869     flush_sequence();
4870
4871     /* test showing child with hidden parent */
4872
4873     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4874                              0, 0, 10, 10, hparent, 0, 0, NULL);
4875     ok (hchild != 0, "Failed to create child window\n");
4876     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4877
4878     ShowWindow( hchild, SW_MINIMIZE );
4879     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4880     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4881     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4882
4883     /* repeat */
4884     flush_events();
4885     flush_sequence();
4886     ShowWindow( hchild, SW_MINIMIZE );
4887     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4888
4889     DestroyWindow(hchild);
4890     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4891                              0, 0, 10, 10, hparent, 0, 0, NULL);
4892     flush_sequence();
4893
4894     ShowWindow( hchild, SW_MAXIMIZE );
4895     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4896     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4897     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4898
4899     /* repeat */
4900     flush_events();
4901     flush_sequence();
4902     ShowWindow( hchild, SW_MAXIMIZE );
4903     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4904
4905     DestroyWindow(hchild);
4906     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4907                              0, 0, 10, 10, hparent, 0, 0, NULL);
4908     flush_sequence();
4909
4910     ShowWindow( hchild, SW_RESTORE );
4911     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4912     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4913     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4914
4915     DestroyWindow(hchild);
4916     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4917                              0, 0, 10, 10, hparent, 0, 0, NULL);
4918     flush_sequence();
4919
4920     ShowWindow( hchild, SW_SHOWMINIMIZED );
4921     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4922     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4923     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4924
4925     /* repeat */
4926     flush_events();
4927     flush_sequence();
4928     ShowWindow( hchild, SW_SHOWMINIMIZED );
4929     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4930
4931     DestroyWindow(hchild);
4932     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4933                              0, 0, 10, 10, hparent, 0, 0, NULL);
4934     flush_sequence();
4935
4936     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4937     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4938     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4939     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4940     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4941
4942     DestroyWindow(hchild);
4943     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4944                              0, 0, 10, 10, hparent, 0, 0, NULL);
4945     flush_sequence();
4946
4947     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4948     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4949     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4950     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4951
4952     /* repeat */
4953     flush_events();
4954     flush_sequence();
4955     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4956     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4957
4958     DestroyWindow(hchild);
4959     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4960                              0, 0, 10, 10, hparent, 0, 0, NULL);
4961     flush_sequence();
4962
4963     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4964     ShowWindow( hchild, SW_FORCEMINIMIZE );
4965     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4966 todo_wine {
4967     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4968 }
4969     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4970
4971     DestroyWindow(hchild);
4972     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4973                              0, 0, 10, 10, hparent, 0, 0, NULL);
4974     flush_sequence();
4975
4976     ShowWindow( hchild, SW_SHOWNA );
4977     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4978     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4979     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4980
4981     /* repeat */
4982     flush_events();
4983     flush_sequence();
4984     ShowWindow( hchild, SW_SHOWNA );
4985     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4986
4987     DestroyWindow(hchild);
4988     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4989                              0, 0, 10, 10, hparent, 0, 0, NULL);
4990     flush_sequence();
4991
4992     ShowWindow( hchild, SW_SHOW );
4993     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4994     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4995     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4996
4997     /* repeat */
4998     flush_events();
4999     flush_sequence();
5000     ShowWindow( hchild, SW_SHOW );
5001     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5002
5003     ShowWindow( hchild, SW_HIDE );
5004     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5005     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5006     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5007
5008     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5009     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5010     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5011     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5012
5013     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5014     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5015     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5016     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5017
5018     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5019     flush_sequence();
5020     DestroyWindow(hchild);
5021     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5022
5023     DestroyWindow(hparent);
5024     flush_sequence();
5025 }
5026
5027 /****************** button message test *************************/
5028 static const struct message WmSetFocusButtonSeq[] =
5029 {
5030     { HCBT_SETFOCUS, hook },
5031     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5032     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5033     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5034     { WM_SETFOCUS, sent|wparam, 0 },
5035     { WM_CTLCOLORBTN, sent|defwinproc },
5036     { 0 }
5037 };
5038 static const struct message WmKillFocusButtonSeq[] =
5039 {
5040     { HCBT_SETFOCUS, hook },
5041     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5042     { WM_KILLFOCUS, sent|wparam, 0 },
5043     { WM_CTLCOLORBTN, sent|defwinproc },
5044     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5045     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5046     { 0 }
5047 };
5048 static const struct message WmSetFocusStaticSeq[] =
5049 {
5050     { HCBT_SETFOCUS, hook },
5051     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5052     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5053     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5054     { WM_SETFOCUS, sent|wparam, 0 },
5055     { WM_CTLCOLORSTATIC, sent|defwinproc },
5056     { 0 }
5057 };
5058 static const struct message WmKillFocusStaticSeq[] =
5059 {
5060     { HCBT_SETFOCUS, hook },
5061     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5062     { WM_KILLFOCUS, sent|wparam, 0 },
5063     { WM_CTLCOLORSTATIC, sent|defwinproc },
5064     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5065     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5066     { 0 }
5067 };
5068 static const struct message WmLButtonDownSeq[] =
5069 {
5070     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5071     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5072     { HCBT_SETFOCUS, hook },
5073     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5074     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5075     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5076     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5077     { WM_CTLCOLORBTN, sent|defwinproc },
5078     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5079     { WM_CTLCOLORBTN, sent|defwinproc },
5080     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5081     { 0 }
5082 };
5083 static const struct message WmLButtonUpSeq[] =
5084 {
5085     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5086     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5087     { WM_CTLCOLORBTN, sent|defwinproc },
5088     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5089     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5090     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5091     { 0 }
5092 };
5093 static const struct message WmSetFontButtonSeq[] =
5094 {
5095     { WM_SETFONT, sent },
5096     { WM_PAINT, sent },
5097     { WM_ERASEBKGND, sent|defwinproc|optional },
5098     { WM_CTLCOLORBTN, sent|defwinproc },
5099     { 0 }
5100 };
5101
5102 static WNDPROC old_button_proc;
5103
5104 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5105 {
5106     static long defwndproc_counter = 0;
5107     LRESULT ret;
5108     struct recvd_message msg;
5109
5110     switch (message)
5111     {
5112     case WM_GETICON:
5113     case WM_GETOBJECT:
5114         return 0;  /* ignore them */
5115     case WM_SYNCPAINT:
5116         break;
5117     case BM_SETSTATE:
5118         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5119         /* fall through */
5120     default:
5121         msg.hwnd = hwnd;
5122         msg.message = message;
5123         msg.flags = sent|wparam|lparam;
5124         if (defwndproc_counter) msg.flags |= defwinproc;
5125         msg.wParam = wParam;
5126         msg.lParam = lParam;
5127         msg.descr = "button";
5128         add_message(&msg);
5129     }
5130
5131     defwndproc_counter++;
5132     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5133     defwndproc_counter--;
5134
5135     return ret;
5136 }
5137
5138 static void subclass_button(void)
5139 {
5140     WNDCLASSA cls;
5141
5142     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5143
5144     old_button_proc = cls.lpfnWndProc;
5145
5146     cls.hInstance = GetModuleHandle(0);
5147     cls.lpfnWndProc = button_hook_proc;
5148     cls.lpszClassName = "my_button_class";
5149     UnregisterClass(cls.lpszClassName, cls.hInstance);
5150     if (!RegisterClassA(&cls)) assert(0);
5151 }
5152
5153 static void test_button_messages(void)
5154 {
5155     static const struct
5156     {
5157         DWORD style;
5158         DWORD dlg_code;
5159         const struct message *setfocus;
5160         const struct message *killfocus;
5161     } button[] = {
5162         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5163           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5164         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5165           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5166         { BS_CHECKBOX, DLGC_BUTTON,
5167           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5168         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5169           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5170         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5171           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5172         { BS_3STATE, DLGC_BUTTON,
5173           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5174         { BS_AUTO3STATE, DLGC_BUTTON,
5175           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5176         { BS_GROUPBOX, DLGC_STATIC,
5177           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5178         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5179           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5180         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5181           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5182         { BS_OWNERDRAW, DLGC_BUTTON,
5183           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
5184     };
5185     unsigned int i;
5186     HWND hwnd;
5187     DWORD dlg_code;
5188     HFONT zfont;
5189
5190     subclass_button();
5191
5192     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5193     {
5194         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
5195                                0, 0, 50, 14, 0, 0, 0, NULL);
5196         ok(hwnd != 0, "Failed to create button window\n");
5197
5198         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5199         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5200
5201         ShowWindow(hwnd, SW_SHOW);
5202         UpdateWindow(hwnd);
5203         SetFocus(0);
5204         flush_sequence();
5205
5206         trace("button style %08x\n", button[i].style);
5207         SetFocus(hwnd);
5208         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5209
5210         SetFocus(0);
5211         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5212
5213         DestroyWindow(hwnd);
5214     }
5215
5216     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5217                            0, 0, 50, 14, 0, 0, 0, NULL);
5218     ok(hwnd != 0, "Failed to create button window\n");
5219
5220     SetForegroundWindow(hwnd);
5221     flush_events();
5222
5223     SetActiveWindow(hwnd);
5224     SetFocus(0);
5225     flush_sequence();
5226
5227     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5228     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5229
5230     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5231     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5232
5233     flush_sequence();
5234     zfont = GetStockObject(SYSTEM_FONT);
5235     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5236     UpdateWindow(hwnd);
5237     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5238
5239     DestroyWindow(hwnd);
5240 }
5241
5242 /****************** static message test *************************/
5243 static const struct message WmSetFontStaticSeq[] =
5244 {
5245     { WM_SETFONT, sent },
5246     { WM_PAINT, sent|defwinproc|optional },
5247     { WM_ERASEBKGND, sent|defwinproc|optional },
5248     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5249     { 0 }
5250 };
5251
5252 static WNDPROC old_static_proc;
5253
5254 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5255 {
5256     static long defwndproc_counter = 0;
5257     LRESULT ret;
5258     struct recvd_message msg;
5259
5260     if (message == WM_GETICON || message == WM_GETOBJECT) return 0;  /* ignore them */
5261
5262     msg.hwnd = hwnd;
5263     msg.message = message;
5264     msg.flags = sent|wparam|lparam;
5265     if (defwndproc_counter) msg.flags |= defwinproc;
5266     msg.wParam = wParam;
5267     msg.lParam = lParam;
5268     msg.descr = "static";
5269     add_message(&msg);
5270
5271     defwndproc_counter++;
5272     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5273     defwndproc_counter--;
5274
5275     return ret;
5276 }
5277
5278 static void subclass_static(void)
5279 {
5280     WNDCLASSA cls;
5281
5282     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5283
5284     old_static_proc = cls.lpfnWndProc;
5285
5286     cls.hInstance = GetModuleHandle(0);
5287     cls.lpfnWndProc = static_hook_proc;
5288     cls.lpszClassName = "my_static_class";
5289     UnregisterClass(cls.lpszClassName, cls.hInstance);
5290     if (!RegisterClassA(&cls)) assert(0);
5291 }
5292
5293 static void test_static_messages(void)
5294 {
5295     /* FIXME: make as comprehensive as the button message test */
5296     static const struct
5297     {
5298         DWORD style;
5299         DWORD dlg_code;
5300         const struct message *setfont;
5301     } static_ctrl[] = {
5302         { SS_LEFT, DLGC_STATIC,
5303           WmSetFontStaticSeq }
5304     };
5305     unsigned int i;
5306     HWND hwnd;
5307     DWORD dlg_code;
5308
5309     subclass_static();
5310
5311     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5312     {
5313         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5314                                0, 0, 50, 14, 0, 0, 0, NULL);
5315         ok(hwnd != 0, "Failed to create static window\n");
5316
5317         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5318         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5319
5320         ShowWindow(hwnd, SW_SHOW);
5321         UpdateWindow(hwnd);
5322         SetFocus(0);
5323         flush_sequence();
5324
5325         trace("static style %08x\n", static_ctrl[i].style);
5326         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5327         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5328
5329         DestroyWindow(hwnd);
5330     }
5331 }
5332
5333 /****************** ComboBox message test *************************/
5334 #define ID_COMBOBOX 0x000f
5335
5336 static const struct message WmKeyDownComboSeq[] =
5337 {
5338     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5339     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5340     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5341     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5342     { WM_CTLCOLOREDIT, sent|parent },
5343     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5344     { 0 }
5345 };
5346
5347 static WNDPROC old_combobox_proc;
5348
5349 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5350 {
5351     static long defwndproc_counter = 0;
5352     LRESULT ret;
5353     struct recvd_message msg;
5354
5355     /* do not log painting messages */
5356     if (message != WM_PAINT &&
5357         message != WM_NCPAINT &&
5358         message != WM_SYNCPAINT &&
5359         message != WM_ERASEBKGND &&
5360         message != WM_NCHITTEST &&
5361         message != WM_GETTEXT &&
5362         message != WM_GETICON &&
5363         message != WM_GETOBJECT &&
5364         message != WM_DEVICECHANGE)
5365     {
5366         msg.hwnd = hwnd;
5367         msg.message = message;
5368         msg.flags = sent|wparam|lparam;
5369         if (defwndproc_counter) msg.flags |= defwinproc;
5370         msg.wParam = wParam;
5371         msg.lParam = lParam;
5372         msg.descr = "combo";
5373         add_message(&msg);
5374     }
5375
5376     defwndproc_counter++;
5377     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5378     defwndproc_counter--;
5379
5380     return ret;
5381 }
5382
5383 static void subclass_combobox(void)
5384 {
5385     WNDCLASSA cls;
5386
5387     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5388
5389     old_combobox_proc = cls.lpfnWndProc;
5390
5391     cls.hInstance = GetModuleHandle(0);
5392     cls.lpfnWndProc = combobox_hook_proc;
5393     cls.lpszClassName = "my_combobox_class";
5394     UnregisterClass(cls.lpszClassName, cls.hInstance);
5395     if (!RegisterClassA(&cls)) assert(0);
5396 }
5397
5398 static void test_combobox_messages(void)
5399 {
5400     HWND parent, combo;
5401     LRESULT ret;
5402
5403     subclass_combobox();
5404
5405     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5406                              100, 100, 200, 200, 0, 0, 0, NULL);
5407     ok(parent != 0, "Failed to create parent window\n");
5408     flush_sequence();
5409
5410     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5411                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5412     ok(combo != 0, "Failed to create combobox window\n");
5413
5414     UpdateWindow(combo);
5415
5416     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5417     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5418
5419     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5420     ok(ret == 0, "expected 0, got %ld\n", ret);
5421     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5422     ok(ret == 1, "expected 1, got %ld\n", ret);
5423     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5424     ok(ret == 2, "expected 2, got %ld\n", ret);
5425
5426     SendMessage(combo, CB_SETCURSEL, 0, 0);
5427     SetFocus(combo);
5428     flush_sequence();
5429
5430     log_all_parent_messages++;
5431     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5432     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5433     log_all_parent_messages--;
5434     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5435
5436     DestroyWindow(combo);
5437     DestroyWindow(parent);
5438 }
5439
5440 /****************** WM_IME_KEYDOWN message test *******************/
5441
5442 static const struct message WmImeKeydownMsgSeq_0[] =
5443 {
5444     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5445     { WM_CHAR, wparam, 'A' },
5446     { 0 }
5447 };
5448
5449 static const struct message WmImeKeydownMsgSeq_1[] =
5450 {
5451     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5452     { WM_CHAR,    optional|wparam, VK_RETURN },
5453     { 0 }
5454 };
5455
5456 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5457 {
5458     struct recvd_message msg;
5459
5460     msg.hwnd = hwnd;
5461     msg.message = message;
5462     msg.flags = wparam|lparam;
5463     msg.wParam = wParam;
5464     msg.lParam = lParam;
5465     msg.descr = "wmime_keydown";
5466     add_message(&msg);
5467
5468     return DefWindowProcA(hwnd, message, wParam, lParam);
5469 }
5470
5471 static void register_wmime_keydown_class(void)
5472 {
5473     WNDCLASSA cls;
5474
5475     ZeroMemory(&cls, sizeof(WNDCLASSA));
5476     cls.lpfnWndProc = wmime_keydown_procA;
5477     cls.hInstance = GetModuleHandleA(0);
5478     cls.lpszClassName = "wmime_keydown_class";
5479     if (!RegisterClassA(&cls)) assert(0);
5480 }
5481
5482 static void test_wmime_keydown_message(void)
5483 {
5484     HWND hwnd;
5485     MSG msg;
5486
5487     trace("Message sequences by WM_IME_KEYDOWN\n");
5488
5489     register_wmime_keydown_class();
5490     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5491                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5492                            NULL, NULL, 0);
5493     flush_events();
5494     flush_sequence();
5495
5496     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5497     SendMessage(hwnd, WM_CHAR, 'A', 1);
5498     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5499
5500     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5501     {
5502         TranslateMessage(&msg);
5503         DispatchMessage(&msg);
5504     }
5505     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5506
5507     DestroyWindow(hwnd);
5508 }
5509
5510 /************* painting message test ********************/
5511
5512 void dump_region(HRGN hrgn)
5513 {
5514     DWORD i, size;
5515     RGNDATA *data = NULL;
5516     RECT *rect;
5517
5518     if (!hrgn)
5519     {
5520         printf( "null region\n" );
5521         return;
5522     }
5523     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5524     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5525     GetRegionData( hrgn, size, data );
5526     printf("%d rects:", data->rdh.nCount );
5527     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5528         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5529     printf("\n");
5530     HeapFree( GetProcessHeap(), 0, data );
5531 }
5532
5533 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5534 {
5535     INT ret;
5536     RECT r1, r2;
5537     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5538     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5539
5540     ret = GetUpdateRgn( hwnd, update, FALSE );
5541     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5542     if (ret == NULLREGION)
5543     {
5544         ok( !hrgn, "Update region shouldn't be empty\n" );
5545     }
5546     else
5547     {
5548         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5549         {
5550             ok( 0, "Regions are different\n" );
5551             if (winetest_debug > 0)
5552             {
5553                 printf( "Update region: " );
5554                 dump_region( update );
5555                 printf( "Wanted region: " );
5556                 dump_region( hrgn );
5557             }
5558         }
5559     }
5560     GetRgnBox( update, &r1 );
5561     GetUpdateRect( hwnd, &r2, FALSE );
5562     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5563         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5564         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5565
5566     DeleteObject( tmp );
5567     DeleteObject( update );
5568 }
5569
5570 static const struct message WmInvalidateRgn[] = {
5571     { WM_NCPAINT, sent },
5572     { WM_GETTEXT, sent|defwinproc|optional },
5573     { 0 }
5574 };
5575
5576 static const struct message WmGetUpdateRect[] = {
5577     { WM_NCPAINT, sent },
5578     { WM_GETTEXT, sent|defwinproc|optional },
5579     { WM_PAINT, sent },
5580     { 0 }
5581 };
5582
5583 static const struct message WmInvalidateFull[] = {
5584     { WM_NCPAINT, sent|wparam, 1 },
5585     { WM_GETTEXT, sent|defwinproc|optional },
5586     { 0 }
5587 };
5588
5589 static const struct message WmInvalidateErase[] = {
5590     { WM_NCPAINT, sent|wparam, 1 },
5591     { WM_GETTEXT, sent|defwinproc|optional },
5592     { WM_ERASEBKGND, sent },
5593     { 0 }
5594 };
5595
5596 static const struct message WmInvalidatePaint[] = {
5597     { WM_PAINT, sent },
5598     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5599     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5600     { 0 }
5601 };
5602
5603 static const struct message WmInvalidateErasePaint[] = {
5604     { WM_PAINT, sent },
5605     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5606     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5607     { WM_ERASEBKGND, sent|beginpaint },
5608     { 0 }
5609 };
5610
5611 static const struct message WmInvalidateErasePaint2[] = {
5612     { WM_PAINT, sent },
5613     { WM_NCPAINT, sent|beginpaint },
5614     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5615     { WM_ERASEBKGND, sent|beginpaint|optional },
5616     { 0 }
5617 };
5618
5619 static const struct message WmErase[] = {
5620     { WM_ERASEBKGND, sent },
5621     { 0 }
5622 };
5623
5624 static const struct message WmPaint[] = {
5625     { WM_PAINT, sent },
5626     { 0 }
5627 };
5628
5629 static const struct message WmParentOnlyPaint[] = {
5630     { WM_PAINT, sent|parent },
5631     { 0 }
5632 };
5633
5634 static const struct message WmInvalidateParent[] = {
5635     { WM_NCPAINT, sent|parent },
5636     { WM_GETTEXT, sent|defwinproc|parent|optional },
5637     { WM_ERASEBKGND, sent|parent },
5638     { 0 }
5639 };
5640
5641 static const struct message WmInvalidateParentChild[] = {
5642     { WM_NCPAINT, sent|parent },
5643     { WM_GETTEXT, sent|defwinproc|parent|optional },
5644     { WM_ERASEBKGND, sent|parent },
5645     { WM_NCPAINT, sent },
5646     { WM_GETTEXT, sent|defwinproc|optional },
5647     { WM_ERASEBKGND, sent },
5648     { 0 }
5649 };
5650
5651 static const struct message WmInvalidateParentChild2[] = {
5652     { WM_ERASEBKGND, sent|parent },
5653     { WM_NCPAINT, sent },
5654     { WM_GETTEXT, sent|defwinproc|optional },
5655     { WM_ERASEBKGND, sent },
5656     { 0 }
5657 };
5658
5659 static const struct message WmParentPaint[] = {
5660     { WM_PAINT, sent|parent },
5661     { WM_PAINT, sent },
5662     { 0 }
5663 };
5664
5665 static const struct message WmParentPaintNc[] = {
5666     { WM_PAINT, sent|parent },
5667     { WM_PAINT, sent },
5668     { WM_NCPAINT, sent|beginpaint },
5669     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5670     { WM_ERASEBKGND, sent|beginpaint|optional },
5671     { 0 }
5672 };
5673
5674 static const struct message WmChildPaintNc[] = {
5675     { WM_PAINT, sent },
5676     { WM_NCPAINT, sent|beginpaint },
5677     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5678     { WM_ERASEBKGND, sent|beginpaint },
5679     { 0 }
5680 };
5681
5682 static const struct message WmParentErasePaint[] = {
5683     { WM_PAINT, sent|parent },
5684     { WM_NCPAINT, sent|parent|beginpaint },
5685     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5686     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
5687     { WM_PAINT, sent },
5688     { WM_NCPAINT, sent|beginpaint },
5689     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5690     { WM_ERASEBKGND, sent|beginpaint|optional },
5691     { 0 }
5692 };
5693
5694 static const struct message WmParentOnlyNcPaint[] = {
5695     { WM_PAINT, sent|parent },
5696     { WM_NCPAINT, sent|parent|beginpaint },
5697     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5698     { 0 }
5699 };
5700
5701 static const struct message WmSetParentStyle[] = {
5702     { WM_STYLECHANGING, sent|parent },
5703     { WM_STYLECHANGED, sent|parent },
5704     { 0 }
5705 };
5706
5707 static void test_paint_messages(void)
5708 {
5709     BOOL ret;
5710     RECT rect;
5711     POINT pt;
5712     MSG msg;
5713     HWND hparent, hchild;
5714     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5715     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5716     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5717                                 100, 100, 200, 200, 0, 0, 0, NULL);
5718     ok (hwnd != 0, "Failed to create overlapped window\n");
5719
5720     ShowWindow( hwnd, SW_SHOW );
5721     UpdateWindow( hwnd );
5722     flush_events();
5723     flush_sequence();
5724
5725     check_update_rgn( hwnd, 0 );
5726     SetRectRgn( hrgn, 10, 10, 20, 20 );
5727     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5728     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5729     check_update_rgn( hwnd, hrgn );
5730     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5731     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5732     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5733     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5734     check_update_rgn( hwnd, hrgn );
5735     /* validate everything */
5736     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5737     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5738     check_update_rgn( hwnd, 0 );
5739
5740     /* test empty region */
5741     SetRectRgn( hrgn, 10, 10, 10, 15 );
5742     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5743     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5744     check_update_rgn( hwnd, 0 );
5745     /* test empty rect */
5746     SetRect( &rect, 10, 10, 10, 15 );
5747     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5748     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5749     check_update_rgn( hwnd, 0 );
5750
5751     /* flush pending messages */
5752     flush_events();
5753     flush_sequence();
5754
5755     GetClientRect( hwnd, &rect );
5756     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5757     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5758      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5759      */
5760     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5761     SetRectEmpty( &rect );
5762     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5763     check_update_rgn( hwnd, hrgn );
5764     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5765     flush_events();
5766     ok_sequence( WmPaint, "Paint", FALSE );
5767     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5768     check_update_rgn( hwnd, 0 );
5769
5770     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5771      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5772      */
5773     trace("testing ValidateRect(0, NULL)\n");
5774     SetRectEmpty( &rect );
5775     if (ValidateRect(0, &rect))  /* not supported on Win9x */
5776     {
5777         check_update_rgn( hwnd, hrgn );
5778         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5779         flush_events();
5780         ok_sequence( WmPaint, "Paint", FALSE );
5781         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5782         check_update_rgn( hwnd, 0 );
5783     }
5784
5785     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5786     SetLastError(0xdeadbeef);
5787     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5788     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5789        "wrong error code %d\n", GetLastError());
5790     check_update_rgn( hwnd, 0 );
5791     flush_events();
5792     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5793
5794     trace("testing ValidateRgn(0, NULL)\n");
5795     SetLastError(0xdeadbeef);
5796     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5797     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
5798        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
5799        "wrong error code %d\n", GetLastError());
5800     check_update_rgn( hwnd, 0 );
5801     flush_events();
5802     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5803
5804     /* now with frame */
5805     SetRectRgn( hrgn, -5, -5, 20, 20 );
5806
5807     /* flush pending messages */
5808     flush_events();
5809     flush_sequence();
5810     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5811     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5812
5813     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5814     check_update_rgn( hwnd, hrgn );
5815
5816     flush_sequence();
5817     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5818     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5819
5820     flush_sequence();
5821     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5822     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5823
5824     GetClientRect( hwnd, &rect );
5825     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5826     check_update_rgn( hwnd, hrgn );
5827
5828     flush_sequence();
5829     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5830     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5831
5832     flush_sequence();
5833     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5834     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5835     check_update_rgn( hwnd, 0 );
5836
5837     flush_sequence();
5838     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5839     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5840     check_update_rgn( hwnd, 0 );
5841
5842     flush_sequence();
5843     SetRectRgn( hrgn, 0, 0, 100, 100 );
5844     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5845     SetRectRgn( hrgn, 0, 0, 50, 100 );
5846     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5847     SetRectRgn( hrgn, 50, 0, 100, 100 );
5848     check_update_rgn( hwnd, hrgn );
5849     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5850     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5851     check_update_rgn( hwnd, 0 );
5852
5853     flush_sequence();
5854     SetRectRgn( hrgn, 0, 0, 100, 100 );
5855     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5856     SetRectRgn( hrgn, 0, 0, 100, 50 );
5857     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5858     ok_sequence( WmErase, "Erase", FALSE );
5859     SetRectRgn( hrgn, 0, 50, 100, 100 );
5860     check_update_rgn( hwnd, hrgn );
5861
5862     flush_sequence();
5863     SetRectRgn( hrgn, 0, 0, 100, 100 );
5864     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5865     SetRectRgn( hrgn, 0, 0, 50, 50 );
5866     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5867     ok_sequence( WmPaint, "Paint", FALSE );
5868
5869     flush_sequence();
5870     SetRectRgn( hrgn, -4, -4, -2, -2 );
5871     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5872     SetRectRgn( hrgn, -200, -200, -198, -198 );
5873     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5874     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5875
5876     flush_sequence();
5877     SetRectRgn( hrgn, -4, -4, -2, -2 );
5878     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5879     SetRectRgn( hrgn, -4, -4, -3, -3 );
5880     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5881     SetRectRgn( hrgn, 0, 0, 1, 1 );
5882     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5883     ok_sequence( WmPaint, "Paint", FALSE );
5884
5885     flush_sequence();
5886     SetRectRgn( hrgn, -4, -4, -1, -1 );
5887     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5888     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5889     /* make sure no WM_PAINT was generated */
5890     flush_events();
5891     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5892
5893     flush_sequence();
5894     SetRectRgn( hrgn, -4, -4, -1, -1 );
5895     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5896     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5897     {
5898         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5899         {
5900             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5901             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5902             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5903             ret = GetUpdateRect( hwnd, &rect, FALSE );
5904             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5905             /* this will send WM_NCPAINT and validate the non client area */
5906             ret = GetUpdateRect( hwnd, &rect, TRUE );
5907             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5908         }
5909         DispatchMessage( &msg );
5910     }
5911     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5912
5913     DestroyWindow( hwnd );
5914
5915     /* now test with a child window */
5916
5917     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5918                               100, 100, 200, 200, 0, 0, 0, NULL);
5919     ok (hparent != 0, "Failed to create parent window\n");
5920
5921     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5922                            10, 10, 100, 100, hparent, 0, 0, NULL);
5923     ok (hchild != 0, "Failed to create child window\n");
5924
5925     ShowWindow( hparent, SW_SHOW );
5926     UpdateWindow( hparent );
5927     UpdateWindow( hchild );
5928     flush_events();
5929     flush_sequence();
5930     log_all_parent_messages++;
5931
5932     SetRect( &rect, 0, 0, 50, 50 );
5933     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5934     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5935     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5936
5937     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5938     pt.x = pt.y = 0;
5939     MapWindowPoints( hchild, hparent, &pt, 1 );
5940     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5941     check_update_rgn( hchild, hrgn );
5942     SetRectRgn( hrgn, 0, 0, 50, 50 );
5943     check_update_rgn( hparent, hrgn );
5944     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5945     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5946     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5947     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5948
5949     flush_events();
5950     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5951
5952     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5953     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5954     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5955     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5956     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5957
5958     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5959     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5960     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5961
5962     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5963     flush_sequence();
5964     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5965     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5966     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5967
5968     /* flush all paint messages */
5969     flush_events();
5970     flush_sequence();
5971
5972     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5973     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5974     SetRectRgn( hrgn, 0, 0, 50, 50 );
5975     check_update_rgn( hparent, hrgn );
5976     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5977     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5978     SetRectRgn( hrgn, 0, 0, 50, 50 );
5979     check_update_rgn( hparent, hrgn );
5980
5981     /* flush all paint messages */
5982     flush_events();
5983     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5984     flush_sequence();
5985
5986     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5987     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5988     SetRectRgn( hrgn, 0, 0, 50, 50 );
5989     check_update_rgn( hparent, hrgn );
5990     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5991     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5992     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5993     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5994     check_update_rgn( hparent, hrgn );
5995     /* flush all paint messages */
5996     flush_events();
5997     flush_sequence();
5998
5999     /* same as above but parent gets completely validated */
6000     SetRect( &rect, 20, 20, 30, 30 );
6001     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6002     SetRectRgn( hrgn, 20, 20, 30, 30 );
6003     check_update_rgn( hparent, hrgn );
6004     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6005     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6006     check_update_rgn( hparent, 0 );  /* no update region */
6007     flush_events();
6008     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6009
6010     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6011     flush_sequence();
6012     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6013     SetRectRgn( hrgn, 20, 20, 30, 30 );
6014     check_update_rgn( hparent, hrgn );
6015     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6016     SetRectRgn( hrgn, 20, 20, 30, 30 );
6017     check_update_rgn( hparent, hrgn );
6018
6019     /* same as above but normal WM_PAINT doesn't validate parent */
6020     flush_sequence();
6021     SetRect( &rect, 20, 20, 30, 30 );
6022     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6023     SetRectRgn( hrgn, 20, 20, 30, 30 );
6024     check_update_rgn( hparent, hrgn );
6025     /* no WM_PAINT in child while parent still pending */
6026     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6027     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6028     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6029     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6030
6031     flush_sequence();
6032     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6033     /* no WM_PAINT in child while parent still pending */
6034     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6035     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6036     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6037     /* now that parent is valid child should get WM_PAINT */
6038     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6039     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6040     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6041     ok_sequence( WmEmptySeq, "No other message", FALSE );
6042
6043     /* same thing with WS_CLIPCHILDREN in parent */
6044     flush_sequence();
6045     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6046     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6047     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6048     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6049     ok_sequence( WmEmptySeq, "No message", FALSE );
6050     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6051     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6052
6053     flush_sequence();
6054     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6055     SetRectRgn( hrgn, 20, 20, 30, 30 );
6056     check_update_rgn( hparent, hrgn );
6057     /* no WM_PAINT in child while parent still pending */
6058     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6059     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6060     /* WM_PAINT in parent first */
6061     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6062     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6063
6064     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6065     flush_sequence();
6066     SetRect( &rect, 0, 0, 30, 30 );
6067     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6068     SetRectRgn( hrgn, 0, 0, 30, 30 );
6069     check_update_rgn( hparent, hrgn );
6070     flush_events();
6071     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6072
6073     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6074     flush_sequence();
6075     SetRect( &rect, -10, 0, 30, 30 );
6076     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6077     SetRect( &rect, 0, 0, 20, 20 );
6078     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6079     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6080     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6081
6082     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6083     flush_sequence();
6084     SetRect( &rect, -10, 0, 30, 30 );
6085     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6086     SetRect( &rect, 0, 0, 100, 100 );
6087     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6088     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6089     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6090     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6091     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6092
6093     /* test RDW_INTERNALPAINT behavior */
6094
6095     flush_sequence();
6096     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6097     flush_events();
6098     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6099
6100     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6101     flush_events();
6102     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6103
6104     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6105     flush_events();
6106     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6107
6108     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6109     UpdateWindow( hparent );
6110     flush_events();
6111     flush_sequence();
6112     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6113     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6114     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6115                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6116     flush_events();
6117     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6118
6119     UpdateWindow( hparent );
6120     flush_events();
6121     flush_sequence();
6122     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6123     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6124     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6125                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6126     flush_events();
6127     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6128
6129     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6130     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6131     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6132     flush_events();
6133     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6134
6135     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6136     UpdateWindow( hparent );
6137     flush_events();
6138     flush_sequence();
6139     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6140     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6141     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6142                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6143     flush_events();
6144     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6145
6146     UpdateWindow( hparent );
6147     flush_events();
6148     flush_sequence();
6149     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6150     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6151     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6152                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6153     flush_events();
6154     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6155
6156     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6157     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6158
6159     UpdateWindow( hparent );
6160     flush_events();
6161     flush_sequence();
6162     trace("testing SetWindowPos(-10000, -10000) on child\n");
6163     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6164     check_update_rgn( hchild, 0 );
6165     flush_events();
6166
6167 #if 0 /* this one doesn't pass under Wine yet */
6168     UpdateWindow( hparent );
6169     flush_events();
6170     flush_sequence();
6171     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6172     ShowWindow( hchild, SW_MINIMIZE );
6173     check_update_rgn( hchild, 0 );
6174     flush_events();
6175 #endif
6176
6177     UpdateWindow( hparent );
6178     flush_events();
6179     flush_sequence();
6180     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6181     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6182     check_update_rgn( hparent, 0 );
6183     flush_events();
6184
6185     log_all_parent_messages--;
6186     DestroyWindow( hparent );
6187     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6188
6189     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6190
6191     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6192                               100, 100, 200, 200, 0, 0, 0, NULL);
6193     ok (hparent != 0, "Failed to create parent window\n");
6194
6195     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6196                            10, 10, 100, 100, hparent, 0, 0, NULL);
6197     ok (hchild != 0, "Failed to create child window\n");
6198
6199     ShowWindow( hparent, SW_SHOW );
6200     UpdateWindow( hparent );
6201     UpdateWindow( hchild );
6202     flush_events();
6203     flush_sequence();
6204
6205     /* moving child outside of parent boundaries changes update region */
6206     SetRect( &rect, 0, 0, 40, 40 );
6207     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6208     SetRectRgn( hrgn, 0, 0, 40, 40 );
6209     check_update_rgn( hchild, hrgn );
6210     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6211     SetRectRgn( hrgn, 10, 0, 40, 40 );
6212     check_update_rgn( hchild, hrgn );
6213     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6214     SetRectRgn( hrgn, 10, 10, 40, 40 );
6215     check_update_rgn( hchild, hrgn );
6216
6217     /* moving parent off-screen does too */
6218     SetRect( &rect, 0, 0, 100, 100 );
6219     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6220     SetRectRgn( hrgn, 0, 0, 100, 100 );
6221     check_update_rgn( hparent, hrgn );
6222     SetRectRgn( hrgn, 10, 10, 40, 40 );
6223     check_update_rgn( hchild, hrgn );
6224     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6225     SetRectRgn( hrgn, 20, 20, 100, 100 );
6226     check_update_rgn( hparent, hrgn );
6227     SetRectRgn( hrgn, 30, 30, 40, 40 );
6228     check_update_rgn( hchild, hrgn );
6229
6230     /* invalidated region is cropped by the parent rects */
6231     SetRect( &rect, 0, 0, 50, 50 );
6232     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6233     SetRectRgn( hrgn, 30, 30, 50, 50 );
6234     check_update_rgn( hchild, hrgn );
6235
6236     DestroyWindow( hparent );
6237     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6238     flush_sequence();
6239
6240     DeleteObject( hrgn );
6241     DeleteObject( hrgn2 );
6242 }
6243
6244 struct wnd_event
6245 {
6246     HWND hwnd;
6247     HANDLE event;
6248 };
6249
6250 static DWORD WINAPI thread_proc(void *param)
6251 {
6252     MSG msg;
6253     struct wnd_event *wnd_event = param;
6254
6255     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6256                                       100, 100, 200, 200, 0, 0, 0, NULL);
6257     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6258
6259     SetEvent(wnd_event->event);
6260
6261     while (GetMessage(&msg, 0, 0, 0))
6262     {
6263         TranslateMessage(&msg);
6264         DispatchMessage(&msg);
6265     }
6266
6267     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6268
6269     return 0;
6270 }
6271
6272 static void test_interthread_messages(void)
6273 {
6274     HANDLE hThread;
6275     DWORD tid;
6276     WNDPROC proc;
6277     MSG msg;
6278     char buf[256];
6279     int len, expected_len;
6280     struct wnd_event wnd_event;
6281     BOOL ret;
6282
6283     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
6284     if (!wnd_event.event)
6285     {
6286         skip("skipping interthread message test under win9x\n");
6287         return;
6288     }
6289
6290     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6291     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6292
6293     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6294
6295     CloseHandle(wnd_event.event);
6296
6297     SetLastError(0xdeadbeef);
6298     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6299     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6300        "wrong error code %d\n", GetLastError());
6301
6302     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6303     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6304
6305     expected_len = lstrlenA("window caption text");
6306     memset(buf, 0, sizeof(buf));
6307     SetLastError(0xdeadbeef);
6308     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6309     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6310     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6311
6312     msg.hwnd = wnd_event.hwnd;
6313     msg.message = WM_GETTEXT;
6314     msg.wParam = sizeof(buf);
6315     msg.lParam = (LPARAM)buf;
6316     memset(buf, 0, sizeof(buf));
6317     SetLastError(0xdeadbeef);
6318     len = DispatchMessageA(&msg);
6319     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6320        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6321
6322     /* the following test causes an exception in user.exe under win9x */
6323     msg.hwnd = wnd_event.hwnd;
6324     msg.message = WM_TIMER;
6325     msg.wParam = 0;
6326     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6327     SetLastError(0xdeadbeef);
6328     len = DispatchMessageA(&msg);
6329     ok(!len && GetLastError() == 0xdeadbeef,
6330        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6331
6332     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6333     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6334
6335     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6336     CloseHandle(hThread);
6337
6338     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6339 }
6340
6341
6342 static const struct message WmVkN[] = {
6343     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6344     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6345     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6346     { WM_CHAR, wparam|lparam, 'n', 1 },
6347     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6348     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6349     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6350     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6351     { 0 }
6352 };
6353 static const struct message WmShiftVkN[] = {
6354     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6355     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6356     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6357     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6358     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6359     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6360     { WM_CHAR, wparam|lparam, 'N', 1 },
6361     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6362     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6363     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6364     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6365     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6366     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6367     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6368     { 0 }
6369 };
6370 static const struct message WmCtrlVkN[] = {
6371     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6372     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6373     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6374     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6375     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6376     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6377     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6378     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6379     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6380     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6381     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6382     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6383     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6384     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6385     { 0 }
6386 };
6387 static const struct message WmCtrlVkN_2[] = {
6388     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6389     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6390     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6391     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6392     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6393     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6394     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6395     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6396     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6397     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6398     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6399     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6400     { 0 }
6401 };
6402 static const struct message WmAltVkN[] = {
6403     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6404     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6405     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6406     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6407     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6408     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6409     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6410     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6411     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6412     { HCBT_SYSCOMMAND, hook },
6413     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6414     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6415     { 0x00AE, sent|defwinproc|optional }, /* XP */
6416     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6417     { WM_INITMENU, sent|defwinproc },
6418     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6419     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6420     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6421     { WM_CAPTURECHANGED, sent|defwinproc },
6422     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6423     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6424     { WM_EXITMENULOOP, sent|defwinproc },
6425     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6426     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6427     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6428     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6429     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6430     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6431     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6432     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6433     { 0 }
6434 };
6435 static const struct message WmAltVkN_2[] = {
6436     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6437     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6438     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6439     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6440     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6441     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6442     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6443     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6444     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6445     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6446     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6447     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6448     { 0 }
6449 };
6450 static const struct message WmCtrlAltVkN[] = {
6451     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6452     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6453     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6454     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6455     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6456     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6457     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6458     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6459     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6460     { WM_CHAR, optional },
6461     { WM_CHAR, sent|optional },
6462     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6463     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6464     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6465     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6466     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6467     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6468     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6469     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6470     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6471     { 0 }
6472 };
6473 static const struct message WmCtrlShiftVkN[] = {
6474     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6475     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6476     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6477     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6478     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6479     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6480     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6481     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6482     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6483     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6484     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6485     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6486     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6487     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6488     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6489     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6490     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6491     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6492     { 0 }
6493 };
6494 static const struct message WmCtrlAltShiftVkN[] = {
6495     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6496     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6497     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6498     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6499     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6500     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6501     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6502     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6503     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6504     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6505     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6506     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6507     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6508     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6509     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6510     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6511     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6512     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6513     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6514     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6515     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6516     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6517     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6518     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6519     { 0 }
6520 };
6521 static const struct message WmAltPressRelease[] = {
6522     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6523     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6524     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6525     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6526     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6527     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6528     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6529     { HCBT_SYSCOMMAND, hook },
6530     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6531     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6532     { WM_INITMENU, sent|defwinproc },
6533     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6534     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6535     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6536
6537     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6538
6539     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6540     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6541     { WM_CAPTURECHANGED, sent|defwinproc },
6542     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6543     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6544     { WM_EXITMENULOOP, sent|defwinproc },
6545     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6546     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6547     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6548     { 0 }
6549 };
6550 static const struct message WmShiftMouseButton[] = {
6551     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6552     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6553     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6554     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6555     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6556     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
6557     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
6558     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
6559     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
6560     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6561     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6562     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6563     { 0 }
6564 };
6565 static const struct message WmF1Seq[] = {
6566     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6567     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6568     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6569     { WM_KEYF1, wparam|lparam, 0, 0 },
6570     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6571     { WM_HELP, sent|defwinproc },
6572     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6573     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6574     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6575     { 0 }
6576 };
6577 static const struct message WmVkAppsSeq[] = {
6578     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6579     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6580     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6581     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6582     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6583     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6584     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6585     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6586     { 0 }
6587 };
6588
6589 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6590 {
6591     MSG msg;
6592
6593     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6594     {
6595         struct recvd_message log_msg;
6596
6597         /* ignore some unwanted messages */
6598         if (msg.message == WM_MOUSEMOVE ||
6599             msg.message == WM_GETICON ||
6600             msg.message == WM_GETOBJECT ||
6601             msg.message == WM_TIMER ||
6602             msg.message == WM_DEVICECHANGE)
6603             continue;
6604
6605         log_msg.hwnd = msg.hwnd;
6606         log_msg.message = msg.message;
6607         log_msg.flags = wparam|lparam;
6608         log_msg.wParam = msg.wParam;
6609         log_msg.lParam = msg.lParam;
6610         log_msg.descr = "accel";
6611         add_message(&log_msg);
6612
6613         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6614         {
6615             TranslateMessage(&msg);
6616             DispatchMessage(&msg);
6617         }
6618     }
6619 }
6620
6621 static void test_accelerators(void)
6622 {
6623     RECT rc;
6624     POINT pt;
6625     SHORT state;
6626     HACCEL hAccel;
6627     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6628                                 100, 100, 200, 200, 0, 0, 0, NULL);
6629     BOOL ret;
6630
6631     assert(hwnd != 0);
6632     UpdateWindow(hwnd);
6633     flush_events();
6634     flush_sequence();
6635
6636     SetFocus(hwnd);
6637     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6638
6639     state = GetKeyState(VK_SHIFT);
6640     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6641     state = GetKeyState(VK_CAPITAL);
6642     ok(state == 0, "wrong CapsLock state %04x\n", state);
6643
6644     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6645     assert(hAccel != 0);
6646
6647     flush_events();
6648     pump_msg_loop(hwnd, 0);
6649     flush_sequence();
6650
6651     trace("testing VK_N press/release\n");
6652     flush_sequence();
6653     keybd_event('N', 0, 0, 0);
6654     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6655     pump_msg_loop(hwnd, hAccel);
6656     if (!sequence_cnt)  /* we didn't get any message */
6657     {
6658         skip( "queuing key events not supported\n" );
6659         goto done;
6660     }
6661     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6662
6663     trace("testing Shift+VK_N press/release\n");
6664     flush_sequence();
6665     keybd_event(VK_SHIFT, 0, 0, 0);
6666     keybd_event('N', 0, 0, 0);
6667     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6668     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6669     pump_msg_loop(hwnd, hAccel);
6670     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6671
6672     trace("testing Ctrl+VK_N press/release\n");
6673     flush_sequence();
6674     keybd_event(VK_CONTROL, 0, 0, 0);
6675     keybd_event('N', 0, 0, 0);
6676     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6677     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6678     pump_msg_loop(hwnd, hAccel);
6679     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6680
6681     trace("testing Alt+VK_N press/release\n");
6682     flush_sequence();
6683     keybd_event(VK_MENU, 0, 0, 0);
6684     keybd_event('N', 0, 0, 0);
6685     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6686     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6687     pump_msg_loop(hwnd, hAccel);
6688     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6689
6690     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6691     flush_sequence();
6692     keybd_event(VK_CONTROL, 0, 0, 0);
6693     keybd_event(VK_MENU, 0, 0, 0);
6694     keybd_event('N', 0, 0, 0);
6695     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6696     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6697     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6698     pump_msg_loop(hwnd, hAccel);
6699     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6700
6701     ret = DestroyAcceleratorTable(hAccel);
6702     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6703
6704     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6705     assert(hAccel != 0);
6706
6707     trace("testing VK_N press/release\n");
6708     flush_sequence();
6709     keybd_event('N', 0, 0, 0);
6710     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6711     pump_msg_loop(hwnd, hAccel);
6712     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6713
6714     trace("testing Shift+VK_N press/release\n");
6715     flush_sequence();
6716     keybd_event(VK_SHIFT, 0, 0, 0);
6717     keybd_event('N', 0, 0, 0);
6718     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6719     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6720     pump_msg_loop(hwnd, hAccel);
6721     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6722
6723     trace("testing Ctrl+VK_N press/release 2\n");
6724     flush_sequence();
6725     keybd_event(VK_CONTROL, 0, 0, 0);
6726     keybd_event('N', 0, 0, 0);
6727     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6728     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6729     pump_msg_loop(hwnd, hAccel);
6730     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6731
6732     trace("testing Alt+VK_N press/release 2\n");
6733     flush_sequence();
6734     keybd_event(VK_MENU, 0, 0, 0);
6735     keybd_event('N', 0, 0, 0);
6736     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6737     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6738     pump_msg_loop(hwnd, hAccel);
6739     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6740
6741     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6742     flush_sequence();
6743     keybd_event(VK_CONTROL, 0, 0, 0);
6744     keybd_event(VK_MENU, 0, 0, 0);
6745     keybd_event('N', 0, 0, 0);
6746     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6747     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6748     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6749     pump_msg_loop(hwnd, hAccel);
6750     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6751
6752     trace("testing Ctrl+Shift+VK_N press/release\n");
6753     flush_sequence();
6754     keybd_event(VK_CONTROL, 0, 0, 0);
6755     keybd_event(VK_SHIFT, 0, 0, 0);
6756     keybd_event('N', 0, 0, 0);
6757     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6758     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6759     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6760     pump_msg_loop(hwnd, hAccel);
6761     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6762
6763     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6764     flush_sequence();
6765     keybd_event(VK_CONTROL, 0, 0, 0);
6766     keybd_event(VK_MENU, 0, 0, 0);
6767     keybd_event(VK_SHIFT, 0, 0, 0);
6768     keybd_event('N', 0, 0, 0);
6769     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6770     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6771     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6772     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6773     pump_msg_loop(hwnd, hAccel);
6774     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6775
6776     ret = DestroyAcceleratorTable(hAccel);
6777     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6778     hAccel = 0;
6779
6780     trace("testing Alt press/release\n");
6781     flush_sequence();
6782     keybd_event(VK_MENU, 0, 0, 0);
6783     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6784     keybd_event(VK_MENU, 0, 0, 0);
6785     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6786     pump_msg_loop(hwnd, 0);
6787     /* this test doesn't pass in Wine for managed windows */
6788     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6789
6790     trace("testing Shift+MouseButton press/release\n");
6791     /* first, move mouse pointer inside of the window client area */
6792     GetClientRect(hwnd, &rc);
6793     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6794     rc.left += (rc.right - rc.left)/2;
6795     rc.top += (rc.bottom - rc.top)/2;
6796     SetCursorPos(rc.left, rc.top);
6797     SetActiveWindow(hwnd);
6798
6799     flush_events();
6800     flush_sequence();
6801     GetCursorPos(&pt);
6802     if (pt.x == rc.left && pt.y == rc.top)
6803     {
6804         keybd_event(VK_SHIFT, 0, 0, 0);
6805         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6806         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6807         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6808         pump_msg_loop(hwnd, 0);
6809         ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
6810     }
6811
6812     trace("testing VK_F1 press/release\n");
6813     keybd_event(VK_F1, 0, 0, 0);
6814     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6815     pump_msg_loop(hwnd, 0);
6816     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6817
6818     trace("testing VK_APPS press/release\n");
6819     keybd_event(VK_APPS, 0, 0, 0);
6820     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6821     pump_msg_loop(hwnd, 0);
6822     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6823 done:
6824     if (hAccel) DestroyAcceleratorTable(hAccel);
6825     DestroyWindow(hwnd);
6826 }
6827
6828 /************* window procedures ********************/
6829
6830 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6831                              WPARAM wParam, LPARAM lParam)
6832 {
6833     static long defwndproc_counter = 0;
6834     static long beginpaint_counter = 0;
6835     LRESULT ret;
6836     struct recvd_message msg;
6837
6838     /* ignore registered messages */
6839     if (message >= 0xc000) return 0;
6840
6841     switch (message)
6842     {
6843         case WM_ENABLE:
6844         {
6845             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6846             ok((BOOL)wParam == !(style & WS_DISABLED),
6847                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6848             break;
6849         }
6850
6851         case WM_CAPTURECHANGED:
6852             if (test_DestroyWindow_flag)
6853             {
6854                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6855                 if (style & WS_CHILD)
6856                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6857                 else if (style & WS_POPUP)
6858                     lParam = WND_POPUP_ID;
6859                 else
6860                     lParam = WND_PARENT_ID;
6861             }
6862             break;
6863
6864         case WM_NCDESTROY:
6865         {
6866             HWND capture;
6867
6868             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6869             capture = GetCapture();
6870             if (capture)
6871             {
6872                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6873                 trace("current capture %p, releasing...\n", capture);
6874                 ReleaseCapture();
6875             }
6876         }
6877         /* fall through */
6878         case WM_DESTROY:
6879             if (pGetAncestor)
6880                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6881             if (test_DestroyWindow_flag)
6882             {
6883                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6884                 if (style & WS_CHILD)
6885                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6886                 else if (style & WS_POPUP)
6887                     lParam = WND_POPUP_ID;
6888                 else
6889                     lParam = WND_PARENT_ID;
6890             }
6891             break;
6892
6893         /* test_accelerators() depends on this */
6894         case WM_NCHITTEST:
6895             return HTCLIENT;
6896
6897         /* ignore */
6898         case WM_MOUSEMOVE:
6899         case WM_MOUSEACTIVATE:
6900         case WM_NCMOUSEMOVE:
6901         case WM_SETCURSOR:
6902         case WM_GETICON:
6903         case WM_GETOBJECT:
6904         case WM_DEVICECHANGE:
6905         case WM_IME_SELECT:
6906             return 0;
6907     }
6908
6909     msg.hwnd = hwnd;
6910     msg.message = message;
6911     msg.flags = sent|wparam|lparam;
6912     if (defwndproc_counter) msg.flags |= defwinproc;
6913     if (beginpaint_counter) msg.flags |= beginpaint;
6914     msg.wParam = wParam;
6915     msg.lParam = lParam;
6916     msg.descr = "MsgCheckProc";
6917     add_message(&msg);
6918
6919     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6920     {
6921         HWND parent = GetParent(hwnd);
6922         RECT rc;
6923         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6924
6925         GetClientRect(parent, &rc);
6926         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6927         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
6928               minmax->ptReserved.x, minmax->ptReserved.y,
6929               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6930               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6931               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6932               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6933
6934         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6935            minmax->ptMaxSize.x, rc.right);
6936         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6937            minmax->ptMaxSize.y, rc.bottom);
6938     }
6939
6940     if (message == WM_PAINT)
6941     {
6942         PAINTSTRUCT ps;
6943         beginpaint_counter++;
6944         BeginPaint( hwnd, &ps );
6945         beginpaint_counter--;
6946         EndPaint( hwnd, &ps );
6947         return 0;
6948     }
6949
6950     defwndproc_counter++;
6951     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
6952                   : DefWindowProcA(hwnd, message, wParam, lParam);
6953     defwndproc_counter--;
6954
6955     return ret;
6956 }
6957
6958 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6959 {
6960     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6961 }
6962
6963 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6964 {
6965     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6966 }
6967
6968 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6969 {
6970     static long defwndproc_counter = 0;
6971     LRESULT ret;
6972     struct recvd_message msg;
6973
6974     switch (message)
6975     {
6976     case WM_GETICON:
6977     case WM_GETOBJECT:
6978         return 0;  /* ignore them */
6979     case WM_QUERYENDSESSION:
6980     case WM_ENDSESSION:
6981         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
6982         break;
6983     }
6984
6985     msg.hwnd = hwnd;
6986     msg.message = message;
6987     msg.flags = sent|wparam|lparam;
6988     if (defwndproc_counter) msg.flags |= defwinproc;
6989     msg.wParam = wParam;
6990     msg.lParam = lParam;
6991     msg.descr = "popup";
6992     add_message(&msg);
6993
6994     if (message == WM_CREATE)
6995     {
6996         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6997         SetWindowLongA(hwnd, GWL_STYLE, style);
6998     }
6999
7000     defwndproc_counter++;
7001     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7002     defwndproc_counter--;
7003
7004     return ret;
7005 }
7006
7007 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7008 {
7009     static long defwndproc_counter = 0;
7010     static long beginpaint_counter = 0;
7011     LRESULT ret;
7012     struct recvd_message msg;
7013
7014     if (message == WM_GETICON || message == WM_GETOBJECT) return 0;  /* ignore them */
7015
7016     /* ignore registered messages */
7017     if (message >= 0xc000) return 0;
7018
7019     if (log_all_parent_messages ||
7020         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7021         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7022         message == WM_ENABLE || message == WM_ENTERIDLE ||
7023         message == WM_DRAWITEM ||
7024         message == WM_IME_SETCONTEXT)
7025     {
7026         switch (message)
7027         {
7028             /* ignore */
7029             case WM_NCHITTEST:
7030                 return HTCLIENT;
7031             case WM_SETCURSOR:
7032             case WM_MOUSEMOVE:
7033             case WM_NCMOUSEMOVE:
7034                 return 0;
7035
7036             case WM_ERASEBKGND:
7037             {
7038                 RECT rc;
7039                 INT ret = GetClipBox((HDC)wParam, &rc);
7040
7041                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7042                        ret, rc.left, rc.top, rc.right, rc.bottom);
7043                 break;
7044             }
7045         }
7046
7047         msg.hwnd = hwnd;
7048         msg.message = message;
7049         msg.flags = sent|parent|wparam|lparam;
7050         if (defwndproc_counter) msg.flags |= defwinproc;
7051         if (beginpaint_counter) msg.flags |= beginpaint;
7052         msg.wParam = wParam;
7053         msg.lParam = lParam;
7054         msg.descr = "parent";
7055         add_message(&msg);
7056     }
7057
7058     if (message == WM_PAINT)
7059     {
7060         PAINTSTRUCT ps;
7061         beginpaint_counter++;
7062         BeginPaint( hwnd, &ps );
7063         beginpaint_counter--;
7064         EndPaint( hwnd, &ps );
7065         return 0;
7066     }
7067
7068     defwndproc_counter++;
7069     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7070     defwndproc_counter--;
7071
7072     return ret;
7073 }
7074
7075 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7076 {
7077     static long defwndproc_counter = 0;
7078     LRESULT ret;
7079     struct recvd_message msg;
7080
7081     if (message == WM_GETICON || message == WM_GETOBJECT) return 0;  /* ignore them */
7082
7083     if (test_def_id)
7084     {
7085         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7086         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7087         if (after_end_dialog)
7088             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7089         else
7090             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7091     }
7092
7093     msg.hwnd = hwnd;
7094     msg.message = message;
7095     msg.flags = sent|wparam|lparam;
7096     if (defwndproc_counter) msg.flags |= defwinproc;
7097     msg.wParam = wParam;
7098     msg.lParam = lParam;
7099     msg.descr = "dialog";
7100     add_message(&msg);
7101
7102     defwndproc_counter++;
7103     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7104     defwndproc_counter--;
7105
7106     return ret;
7107 }
7108
7109 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7110 {
7111     static long defwndproc_counter = 0;
7112     LRESULT ret;
7113     struct recvd_message msg;
7114
7115     /* log only specific messages we are interested in */
7116     switch (message)
7117     {
7118 #if 0 /* probably log these as well */
7119     case WM_ACTIVATE:
7120     case WM_SETFOCUS:
7121     case WM_KILLFOCUS:
7122 #endif
7123     case WM_SHOWWINDOW:
7124     case WM_SIZE:
7125     case WM_MOVE:
7126     case WM_GETMINMAXINFO:
7127     case WM_WINDOWPOSCHANGING:
7128     case WM_WINDOWPOSCHANGED:
7129         break;
7130
7131     default: /* ignore */
7132         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7133         return DefWindowProcA(hwnd, message, wParam, lParam);
7134     }
7135
7136     msg.hwnd = hwnd;
7137     msg.message = message;
7138     msg.flags = sent|wparam|lparam;
7139     if (defwndproc_counter) msg.flags |= defwinproc;
7140     msg.wParam = wParam;
7141     msg.lParam = lParam;
7142     msg.descr = "show";
7143     add_message(&msg);
7144
7145     defwndproc_counter++;
7146     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7147     defwndproc_counter--;
7148
7149     return ret;
7150 }
7151
7152 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7153 {
7154     switch (msg)
7155     {
7156         case WM_CREATE: return 0;
7157         case WM_PAINT:
7158         {
7159             MSG msg2;
7160             static int i = 0;
7161
7162             if (i < 256)
7163             {
7164                 i++;
7165                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7166                 {
7167                     TranslateMessage(&msg2);
7168                     DispatchMessage(&msg2);
7169                 }
7170                 i--;
7171             }
7172             else ok(broken(1), "infinite loop\n");
7173             if ( i == 0)
7174                 paint_loop_done = 1;
7175             return DefWindowProcA(hWnd,msg,wParam,lParam);
7176         }
7177     }
7178     return DefWindowProcA(hWnd,msg,wParam,lParam);
7179 }
7180
7181 static BOOL RegisterWindowClasses(void)
7182 {
7183     WNDCLASSA cls;
7184     WNDCLASSW clsW;
7185
7186     cls.style = 0;
7187     cls.lpfnWndProc = MsgCheckProcA;
7188     cls.cbClsExtra = 0;
7189     cls.cbWndExtra = 0;
7190     cls.hInstance = GetModuleHandleA(0);
7191     cls.hIcon = 0;
7192     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7193     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7194     cls.lpszMenuName = NULL;
7195     cls.lpszClassName = "TestWindowClass";
7196     if(!RegisterClassA(&cls)) return FALSE;
7197
7198     cls.lpfnWndProc = ShowWindowProcA;
7199     cls.lpszClassName = "ShowWindowClass";
7200     if(!RegisterClassA(&cls)) return FALSE;
7201
7202     cls.lpfnWndProc = PopupMsgCheckProcA;
7203     cls.lpszClassName = "TestPopupClass";
7204     if(!RegisterClassA(&cls)) return FALSE;
7205
7206     cls.lpfnWndProc = ParentMsgCheckProcA;
7207     cls.lpszClassName = "TestParentClass";
7208     if(!RegisterClassA(&cls)) return FALSE;
7209
7210     cls.lpfnWndProc = DefWindowProcA;
7211     cls.lpszClassName = "SimpleWindowClass";
7212     if(!RegisterClassA(&cls)) return FALSE;
7213
7214     cls.lpfnWndProc = PaintLoopProcA;
7215     cls.lpszClassName = "PaintLoopWindowClass";
7216     if(!RegisterClassA(&cls)) return FALSE;
7217
7218     cls.style = CS_NOCLOSE;
7219     cls.lpszClassName = "NoCloseWindowClass";
7220     if(!RegisterClassA(&cls)) return FALSE;
7221
7222     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7223     cls.style = 0;
7224     cls.hInstance = GetModuleHandleA(0);
7225     cls.hbrBackground = 0;
7226     cls.lpfnWndProc = TestDlgProcA;
7227     cls.lpszClassName = "TestDialogClass";
7228     if(!RegisterClassA(&cls)) return FALSE;
7229
7230     clsW.style = 0;
7231     clsW.lpfnWndProc = MsgCheckProcW;
7232     clsW.cbClsExtra = 0;
7233     clsW.cbWndExtra = 0;
7234     clsW.hInstance = GetModuleHandleW(0);
7235     clsW.hIcon = 0;
7236     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7237     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7238     clsW.lpszMenuName = NULL;
7239     clsW.lpszClassName = testWindowClassW;
7240     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7241
7242     return TRUE;
7243 }
7244
7245 static BOOL is_our_logged_class(HWND hwnd)
7246 {
7247     char buf[256];
7248
7249     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7250     {
7251         if (!lstrcmpiA(buf, "TestWindowClass") ||
7252             !lstrcmpiA(buf, "ShowWindowClass") ||
7253             !lstrcmpiA(buf, "TestParentClass") ||
7254             !lstrcmpiA(buf, "TestPopupClass") ||
7255             !lstrcmpiA(buf, "SimpleWindowClass") ||
7256             !lstrcmpiA(buf, "TestDialogClass") ||
7257             !lstrcmpiA(buf, "MDI_frame_class") ||
7258             !lstrcmpiA(buf, "MDI_client_class") ||
7259             !lstrcmpiA(buf, "MDI_child_class") ||
7260             !lstrcmpiA(buf, "my_button_class") ||
7261             !lstrcmpiA(buf, "my_edit_class") ||
7262             !lstrcmpiA(buf, "static") ||
7263             !lstrcmpiA(buf, "ListBox") ||
7264             !lstrcmpiA(buf, "ComboBox") ||
7265             !lstrcmpiA(buf, "MyDialogClass") ||
7266             !lstrcmpiA(buf, "#32770") ||
7267             !lstrcmpiA(buf, "#32768"))
7268         return TRUE;
7269     }
7270     return FALSE;
7271 }
7272
7273 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7274
7275     HWND hwnd;
7276
7277     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7278
7279     if (nCode == HCBT_CLICKSKIPPED)
7280     {
7281         /* ignore this event, XP sends it a lot when switching focus between windows */
7282         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7283     }
7284
7285     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7286     {
7287         struct recvd_message msg;
7288
7289         msg.hwnd = 0;
7290         msg.message = nCode;
7291         msg.flags = hook|wparam|lparam;
7292         msg.wParam = wParam;
7293         msg.lParam = lParam;
7294         msg.descr = "CBT";
7295         add_message(&msg);
7296
7297         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7298     }
7299
7300     if (nCode == HCBT_DESTROYWND)
7301     {
7302         if (test_DestroyWindow_flag)
7303         {
7304             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7305             if (style & WS_CHILD)
7306                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7307             else if (style & WS_POPUP)
7308                 lParam = WND_POPUP_ID;
7309             else
7310                 lParam = WND_PARENT_ID;
7311         }
7312     }
7313
7314     /* Log also SetFocus(0) calls */
7315     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7316
7317     if (is_our_logged_class(hwnd))
7318     {
7319         struct recvd_message msg;
7320
7321         msg.hwnd = hwnd;
7322         msg.message = nCode;
7323         msg.flags = hook|wparam|lparam;
7324         msg.wParam = wParam;
7325         msg.lParam = lParam;
7326         msg.descr = "CBT";
7327         add_message(&msg);
7328     }
7329     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7330 }
7331
7332 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7333                                     DWORD event,
7334                                     HWND hwnd,
7335                                     LONG object_id,
7336                                     LONG child_id,
7337                                     DWORD thread_id,
7338                                     DWORD event_time)
7339 {
7340     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7341
7342     /* ignore mouse cursor events */
7343     if (object_id == OBJID_CURSOR) return;
7344
7345     if (!hwnd || is_our_logged_class(hwnd))
7346     {
7347         struct recvd_message msg;
7348
7349         msg.hwnd = hwnd;
7350         msg.message = event;
7351         msg.flags = winevent_hook|wparam|lparam;
7352         msg.wParam = object_id;
7353         msg.lParam = child_id;
7354         msg.descr = "WEH";
7355         add_message(&msg);
7356     }
7357 }
7358
7359 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7360 static const WCHAR wszAnsi[] = {'U',0};
7361
7362 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7363 {
7364     switch (uMsg)
7365     {
7366     case CB_FINDSTRINGEXACT:
7367         trace("String: %p\n", (LPCWSTR)lParam);
7368         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7369             return 1;
7370         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7371             return 0;
7372         return -1;
7373     }
7374     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7375 }
7376
7377 static const struct message WmGetTextLengthAfromW[] = {
7378     { WM_GETTEXTLENGTH, sent },
7379     { WM_GETTEXT, sent|optional },
7380     { 0 }
7381 };
7382
7383 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7384
7385 /* dummy window proc for WM_GETTEXTLENGTH test */
7386 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7387 {
7388     switch(msg)
7389     {
7390     case WM_GETTEXTLENGTH:
7391         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7392     case WM_GETTEXT:
7393         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7394         return lstrlenW( (LPWSTR)lp );
7395     default:
7396         return DefWindowProcW( hwnd, msg, wp, lp );
7397     }
7398 }
7399
7400 static void test_message_conversion(void)
7401 {
7402     static const WCHAR wszMsgConversionClass[] =
7403         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7404     WNDCLASSW cls;
7405     LRESULT lRes;
7406     HWND hwnd;
7407     WNDPROC wndproc, newproc;
7408     BOOL ret;
7409
7410     cls.style = 0;
7411     cls.lpfnWndProc = MsgConversionProcW;
7412     cls.cbClsExtra = 0;
7413     cls.cbWndExtra = 0;
7414     cls.hInstance = GetModuleHandleW(NULL);
7415     cls.hIcon = NULL;
7416     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7417     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7418     cls.lpszMenuName = NULL;
7419     cls.lpszClassName = wszMsgConversionClass;
7420     /* this call will fail on Win9x, but that doesn't matter as this test is
7421      * meaningless on those platforms */
7422     if(!RegisterClassW(&cls)) return;
7423
7424     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7425                            100, 100, 200, 200, 0, 0, 0, NULL);
7426     ok(hwnd != NULL, "Window creation failed\n");
7427
7428     /* {W, A} -> A */
7429
7430     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7431     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7432     ok(lRes == 0, "String should have been converted\n");
7433     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7434     ok(lRes == 1, "String shouldn't have been converted\n");
7435
7436     /* {W, A} -> W */
7437
7438     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7439     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7440     ok(lRes == 1, "String shouldn't have been converted\n");
7441     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7442     ok(lRes == 1, "String shouldn't have been converted\n");
7443
7444     /* Synchronous messages */
7445
7446     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7447     ok(lRes == 0, "String should have been converted\n");
7448     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7449     ok(lRes == 1, "String shouldn't have been converted\n");
7450
7451     /* Asynchronous messages */
7452
7453     SetLastError(0);
7454     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7455     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7456         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7457     SetLastError(0);
7458     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7459     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7460         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7461     SetLastError(0);
7462     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7463     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7464         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7465     SetLastError(0);
7466     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7467     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7468         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7469     SetLastError(0);
7470     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7471     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7472         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7473     SetLastError(0);
7474     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7475     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7476         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7477     SetLastError(0);
7478     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7479     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7480         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7481     SetLastError(0);
7482     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7483     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7484         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7485
7486     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7487
7488     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7489                           WS_OVERLAPPEDWINDOW,
7490                           100, 100, 200, 200, 0, 0, 0, NULL);
7491     assert(hwnd);
7492     flush_sequence();
7493     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7494     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7495     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7496         "got bad length %ld\n", lRes );
7497
7498     flush_sequence();
7499     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7500                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7501     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7502     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7503         "got bad length %ld\n", lRes );
7504
7505     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7506     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7507     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7508     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7509                                      NULL, 0, NULL, NULL ) ||
7510         broken(lRes == lstrlenW(dummy_window_text) + 37),
7511         "got bad length %ld\n", lRes );
7512
7513     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7514     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7515     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7516                                      NULL, 0, NULL, NULL ) ||
7517         broken(lRes == lstrlenW(dummy_window_text) + 37),
7518         "got bad length %ld\n", lRes );
7519
7520     ret = DestroyWindow(hwnd);
7521     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7522 }
7523
7524 struct timer_info
7525 {
7526     HWND hWnd;
7527     HANDLE handles[2];
7528     DWORD id;
7529 };
7530
7531 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7532 {
7533 }
7534
7535 #define TIMER_ID  0x19
7536
7537 static DWORD WINAPI timer_thread_proc(LPVOID x)
7538 {
7539     struct timer_info *info = x;
7540     DWORD r;
7541
7542     r = KillTimer(info->hWnd, 0x19);
7543     ok(r,"KillTimer failed in thread\n");
7544     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7545     ok(r,"SetTimer failed in thread\n");
7546     ok(r==TIMER_ID,"SetTimer id different\n");
7547     r = SetEvent(info->handles[0]);
7548     ok(r,"SetEvent failed in thread\n");
7549     return 0;
7550 }
7551
7552 static void test_timers(void)
7553 {
7554     struct timer_info info;
7555     DWORD id;
7556
7557     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7558        WS_OVERLAPPEDWINDOW ,
7559        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7560        NULL, NULL, 0);
7561
7562     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7563     ok(info.id, "SetTimer failed\n");
7564     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7565     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7566     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7567
7568     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7569
7570     WaitForSingleObject(info.handles[1], INFINITE);
7571
7572     CloseHandle(info.handles[0]);
7573     CloseHandle(info.handles[1]);
7574
7575     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7576
7577     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7578 }
7579
7580 static int count = 0;
7581 static VOID CALLBACK callback_count(
7582     HWND hwnd,
7583     UINT uMsg,
7584     UINT_PTR idEvent,
7585     DWORD dwTime
7586 )
7587 {
7588     count++;
7589 }
7590
7591 static void test_timers_no_wnd(void)
7592 {
7593     UINT_PTR id, id2;
7594     MSG msg;
7595
7596     count = 0;
7597     id = SetTimer(NULL, 0, 100, callback_count);
7598     ok(id != 0, "did not get id from SetTimer.\n");
7599     id2 = SetTimer(NULL, id, 200, callback_count);
7600     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7601     Sleep(150);
7602     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7603     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7604     Sleep(150);
7605     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7606     ok(count == 1, "did not get one count as expected (%i).\n", count);
7607     KillTimer(NULL, id);
7608     Sleep(250);
7609     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7610     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7611 }
7612
7613 /* Various win events with arbitrary parameters */
7614 static const struct message WmWinEventsSeq[] = {
7615     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7616     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7617     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7618     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7619     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7620     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7621     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7622     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7623     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7624     /* our win event hook ignores OBJID_CURSOR events */
7625     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7626     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7627     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7628     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7629     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7630     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7631     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7632     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7633     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7634     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7635     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7636     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7637     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7638     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7639     { 0 }
7640 };
7641 static const struct message WmWinEventCaretSeq[] = {
7642     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7643     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7644     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7645     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7646     { 0 }
7647 };
7648 static const struct message WmWinEventCaretSeq_2[] = {
7649     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7650     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7651     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7652     { 0 }
7653 };
7654 static const struct message WmWinEventAlertSeq[] = {
7655     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7656     { 0 }
7657 };
7658 static const struct message WmWinEventAlertSeq_2[] = {
7659     /* create window in the thread proc */
7660     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7661     /* our test event */
7662     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7663     { 0 }
7664 };
7665 static const struct message WmGlobalHookSeq_1[] = {
7666     /* create window in the thread proc */
7667     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7668     /* our test events */
7669     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7670     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7671     { 0 }
7672 };
7673 static const struct message WmGlobalHookSeq_2[] = {
7674     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7675     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7676     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7677     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7678     { 0 }
7679 };
7680
7681 static const struct message WmMouseLLHookSeq[] = {
7682     { WM_MOUSEMOVE, hook },
7683     { WM_LBUTTONUP, hook },
7684     { WM_MOUSEMOVE, hook },
7685     { 0 }
7686 };
7687
7688 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7689                                          DWORD event,
7690                                          HWND hwnd,
7691                                          LONG object_id,
7692                                          LONG child_id,
7693                                          DWORD thread_id,
7694                                          DWORD event_time)
7695 {
7696     char buf[256];
7697
7698     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7699     {
7700         if (!lstrcmpiA(buf, "TestWindowClass") ||
7701             !lstrcmpiA(buf, "static"))
7702         {
7703             struct recvd_message msg;
7704
7705             msg.hwnd = hwnd;
7706             msg.message = event;
7707             msg.flags = winevent_hook|wparam|lparam;
7708             msg.wParam = object_id;
7709             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7710             msg.descr = "WEH_2";
7711             add_message(&msg);
7712         }
7713     }
7714 }
7715
7716 static HHOOK hCBT_global_hook;
7717 static DWORD cbt_global_hook_thread_id;
7718
7719 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7720
7721     HWND hwnd;
7722     char buf[256];
7723
7724     if (nCode == HCBT_SYSCOMMAND)
7725     {
7726         struct recvd_message msg;
7727
7728         msg.hwnd = 0;
7729         msg.message = nCode;
7730         msg.flags = hook|wparam|lparam;
7731         msg.wParam = wParam;
7732         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7733         msg.descr = "CBT_2";
7734         add_message(&msg);
7735
7736         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7737     }
7738     /* WH_MOUSE_LL hook */
7739     if (nCode == HC_ACTION)
7740     {
7741         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7742
7743         /* we can't test for real mouse events */
7744         if (mhll->flags & LLMHF_INJECTED)
7745         {
7746             struct recvd_message msg;
7747
7748             memset (&msg, 0, sizeof (msg));
7749             msg.message = wParam;
7750             msg.flags = hook;
7751             msg.descr = "CBT_2";
7752             add_message(&msg);
7753         }
7754         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7755     }
7756
7757     /* Log also SetFocus(0) calls */
7758     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7759
7760     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7761     {
7762         if (!lstrcmpiA(buf, "TestWindowClass") ||
7763             !lstrcmpiA(buf, "static"))
7764         {
7765             struct recvd_message msg;
7766
7767             msg.hwnd = hwnd;
7768             msg.message = nCode;
7769             msg.flags = hook|wparam|lparam;
7770             msg.wParam = wParam;
7771             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7772             msg.descr = "CBT_2";
7773             add_message(&msg);
7774         }
7775     }
7776     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7777 }
7778
7779 static DWORD WINAPI win_event_global_thread_proc(void *param)
7780 {
7781     HWND hwnd;
7782     MSG msg;
7783     HANDLE hevent = *(HANDLE *)param;
7784
7785     assert(pNotifyWinEvent);
7786
7787     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7788     assert(hwnd);
7789     trace("created thread window %p\n", hwnd);
7790
7791     *(HWND *)param = hwnd;
7792
7793     flush_sequence();
7794     /* this event should be received only by our new hook proc,
7795      * an old one does not expect an event from another thread.
7796      */
7797     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7798     SetEvent(hevent);
7799
7800     while (GetMessage(&msg, 0, 0, 0))
7801     {
7802         TranslateMessage(&msg);
7803         DispatchMessage(&msg);
7804     }
7805     return 0;
7806 }
7807
7808 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7809 {
7810     HWND hwnd;
7811     MSG msg;
7812     HANDLE hevent = *(HANDLE *)param;
7813
7814     flush_sequence();
7815     /* these events should be received only by our new hook proc,
7816      * an old one does not expect an event from another thread.
7817      */
7818
7819     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7820     assert(hwnd);
7821     trace("created thread window %p\n", hwnd);
7822
7823     *(HWND *)param = hwnd;
7824
7825     /* Windows doesn't like when a thread plays games with the focus,
7826        that leads to all kinds of misbehaviours and failures to activate
7827        a window. So, better keep next lines commented out.
7828     SetFocus(0);
7829     SetFocus(hwnd);*/
7830
7831     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7832     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7833
7834     SetEvent(hevent);
7835
7836     while (GetMessage(&msg, 0, 0, 0))
7837     {
7838         TranslateMessage(&msg);
7839         DispatchMessage(&msg);
7840     }
7841     return 0;
7842 }
7843
7844 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7845 {
7846     HWND hwnd;
7847     MSG msg;
7848     HANDLE hevent = *(HANDLE *)param;
7849
7850     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7851     assert(hwnd);
7852     trace("created thread window %p\n", hwnd);
7853
7854     *(HWND *)param = hwnd;
7855
7856     flush_sequence();
7857
7858     /* Windows doesn't like when a thread plays games with the focus,
7859      * that leads to all kinds of misbehaviours and failures to activate
7860      * a window. So, better don't generate a mouse click message below.
7861      */
7862     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7863     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7864     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7865
7866     SetEvent(hevent);
7867     while (GetMessage(&msg, 0, 0, 0))
7868     {
7869         TranslateMessage(&msg);
7870         DispatchMessage(&msg);
7871     }
7872     return 0;
7873 }
7874
7875 static void test_winevents(void)
7876 {
7877     BOOL ret;
7878     MSG msg;
7879     HWND hwnd, hwnd2;
7880     UINT i;
7881     HANDLE hthread, hevent;
7882     DWORD tid;
7883     HWINEVENTHOOK hhook;
7884     const struct message *events = WmWinEventsSeq;
7885
7886     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7887                            WS_OVERLAPPEDWINDOW,
7888                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7889                            NULL, NULL, 0);
7890     assert(hwnd);
7891
7892     /****** start of global hook test *************/
7893     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7894     if (!hCBT_global_hook)
7895     {
7896         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7897         skip( "cannot set global hook\n" );
7898         return;
7899     }
7900
7901     hevent = CreateEventA(NULL, 0, 0, NULL);
7902     assert(hevent);
7903     hwnd2 = hevent;
7904
7905     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7906     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7907
7908     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7909
7910     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7911
7912     flush_sequence();
7913     /* this one should be received only by old hook proc */
7914     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7915     /* this one should be received only by old hook proc */
7916     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7917
7918     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7919
7920     ret = UnhookWindowsHookEx(hCBT_global_hook);
7921     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7922
7923     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7924     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7925     CloseHandle(hthread);
7926     CloseHandle(hevent);
7927     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7928     /****** end of global hook test *************/
7929
7930     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7931     {
7932         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7933         return;
7934     }
7935
7936     flush_sequence();
7937
7938     if (0)
7939     {
7940     /* this test doesn't pass under Win9x */
7941     /* win2k ignores events with hwnd == 0 */
7942     SetLastError(0xdeadbeef);
7943     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7944     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7945        GetLastError() == 0xdeadbeef, /* Win9x */
7946        "unexpected error %d\n", GetLastError());
7947     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7948     }
7949
7950     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7951         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7952
7953     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7954
7955     /****** start of event filtering test *************/
7956     hhook = pSetWinEventHook(
7957         EVENT_OBJECT_SHOW, /* 0x8002 */
7958         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7959         GetModuleHandleA(0), win_event_global_hook_proc,
7960         GetCurrentProcessId(), 0,
7961         WINEVENT_INCONTEXT);
7962     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7963
7964     hevent = CreateEventA(NULL, 0, 0, NULL);
7965     assert(hevent);
7966     hwnd2 = hevent;
7967
7968     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7969     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7970
7971     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7972
7973     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7974
7975     flush_sequence();
7976     /* this one should be received only by old hook proc */
7977     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7978     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7979     /* this one should be received only by old hook proc */
7980     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7981
7982     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7983
7984     ret = pUnhookWinEvent(hhook);
7985     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7986
7987     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7988     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7989     CloseHandle(hthread);
7990     CloseHandle(hevent);
7991     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7992     /****** end of event filtering test *************/
7993
7994     /****** start of out of context event test *************/
7995     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
7996         win_event_global_hook_proc, GetCurrentProcessId(), 0,
7997         WINEVENT_OUTOFCONTEXT);
7998     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7999
8000     hevent = CreateEventA(NULL, 0, 0, NULL);
8001     assert(hevent);
8002     hwnd2 = hevent;
8003
8004     flush_sequence();
8005
8006     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8007     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8008
8009     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8010
8011     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8012     /* process pending winevent messages */
8013     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8014     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8015
8016     flush_sequence();
8017     /* this one should be received only by old hook proc */
8018     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8019     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8020     /* this one should be received only by old hook proc */
8021     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8022
8023     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8024     /* process pending winevent messages */
8025     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8026     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8027
8028     ret = pUnhookWinEvent(hhook);
8029     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8030
8031     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8032     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8033     CloseHandle(hthread);
8034     CloseHandle(hevent);
8035     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8036     /****** end of out of context event test *************/
8037
8038     /****** start of MOUSE_LL hook test *************/
8039     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8040     /* WH_MOUSE_LL is not supported on Win9x platforms */
8041     if (!hCBT_global_hook)
8042     {
8043         trace("Skipping WH_MOUSE_LL test on this platform\n");
8044         goto skip_mouse_ll_hook_test;
8045     }
8046
8047     hevent = CreateEventA(NULL, 0, 0, NULL);
8048     assert(hevent);
8049     hwnd2 = hevent;
8050
8051     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8052     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8053
8054     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8055         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8056
8057     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8058     flush_sequence();
8059
8060     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8061     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8062     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8063
8064     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8065
8066     ret = UnhookWindowsHookEx(hCBT_global_hook);
8067     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8068
8069     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8070     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8071     CloseHandle(hthread);
8072     CloseHandle(hevent);
8073     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8074     /****** end of MOUSE_LL hook test *************/
8075 skip_mouse_ll_hook_test:
8076
8077     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8078 }
8079
8080 static void test_set_hook(void)
8081 {
8082     BOOL ret;
8083     HHOOK hhook;
8084     HWINEVENTHOOK hwinevent_hook;
8085
8086     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8087     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8088     UnhookWindowsHookEx(hhook);
8089
8090     if (0)
8091     {
8092     /* this test doesn't pass under Win9x: BUG! */
8093     SetLastError(0xdeadbeef);
8094     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8095     ok(!hhook, "global hook requires hModule != 0\n");
8096     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8097     }
8098
8099     SetLastError(0xdeadbeef);
8100     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8101     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8102     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8103        GetLastError() == 0xdeadbeef, /* Win9x */
8104        "unexpected error %d\n", GetLastError());
8105
8106     SetLastError(0xdeadbeef);
8107     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8108     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8109        GetLastError() == 0xdeadbeef, /* Win9x */
8110        "unexpected error %d\n", GetLastError());
8111
8112     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8113
8114     /* even process local incontext hooks require hmodule */
8115     SetLastError(0xdeadbeef);
8116     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8117         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8118     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8119     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8120        GetLastError() == 0xdeadbeef, /* Win9x */
8121        "unexpected error %d\n", GetLastError());
8122
8123     /* even thread local incontext hooks require hmodule */
8124     SetLastError(0xdeadbeef);
8125     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8126         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8127     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8128     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8129        GetLastError() == 0xdeadbeef, /* Win9x */
8130        "unexpected error %d\n", GetLastError());
8131
8132     if (0)
8133     {
8134     /* these 3 tests don't pass under Win9x */
8135     SetLastError(0xdeadbeef);
8136     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8137         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8138     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8139     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8140
8141     SetLastError(0xdeadbeef);
8142     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8143         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8144     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8145     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8146
8147     SetLastError(0xdeadbeef);
8148     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8149         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8150     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8151     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8152     }
8153
8154     SetLastError(0xdeadbeef);
8155     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8156         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8157     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8158     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8159     ret = pUnhookWinEvent(hwinevent_hook);
8160     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8161
8162 todo_wine {
8163     /* This call succeeds under win2k SP4, but fails under Wine.
8164        Does win2k test/use passed process id? */
8165     SetLastError(0xdeadbeef);
8166     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8167         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8168     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8169     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8170     ret = pUnhookWinEvent(hwinevent_hook);
8171     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8172 }
8173
8174     SetLastError(0xdeadbeef);
8175     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8176     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8177         GetLastError() == 0xdeadbeef, /* Win9x */
8178         "unexpected error %d\n", GetLastError());
8179 }
8180
8181 static const struct message ScrollWindowPaint1[] = {
8182     { WM_PAINT, sent },
8183     { WM_ERASEBKGND, sent|beginpaint },
8184     { 0 }
8185 };
8186
8187 static const struct message ScrollWindowPaint2[] = {
8188     { WM_PAINT, sent },
8189     { 0 }
8190 };
8191
8192 static void test_scrollwindowex(void)
8193 {
8194     HWND hwnd, hchild;
8195     RECT rect={0,0,130,130};
8196
8197     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8198             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8199             100, 100, 200, 200, 0, 0, 0, NULL);
8200     ok (hwnd != 0, "Failed to create overlapped window\n");
8201     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8202             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8203             10, 10, 150, 150, hwnd, 0, 0, NULL);
8204     ok (hchild != 0, "Failed to create child\n");
8205     UpdateWindow(hwnd);
8206     flush_events();
8207     flush_sequence();
8208
8209     /* scroll without the child window */
8210     trace("start scroll\n");
8211     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8212             SW_ERASE|SW_INVALIDATE);
8213     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8214     trace("end scroll\n");
8215     flush_sequence();
8216     flush_events();
8217     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8218     flush_events();
8219     flush_sequence();
8220
8221     /* Now without the SW_ERASE flag */
8222     trace("start scroll\n");
8223     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8224     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8225     trace("end scroll\n");
8226     flush_sequence();
8227     flush_events();
8228     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8229     flush_events();
8230     flush_sequence();
8231
8232     /* now scroll the child window as well */
8233     trace("start scroll\n");
8234     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8235             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8236     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8237     /* windows sometimes a WM_MOVE */
8238     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8239     trace("end scroll\n");
8240     flush_sequence();
8241     flush_events();
8242     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8243     flush_events();
8244     flush_sequence();
8245
8246     /* now scroll with ScrollWindow() */
8247     trace("start scroll with ScrollWindow\n");
8248     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8249     trace("end scroll\n");
8250     flush_sequence();
8251     flush_events();
8252     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8253
8254     ok(DestroyWindow(hchild), "failed to destroy window\n");
8255     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8256     flush_sequence();
8257 }
8258
8259 static const struct message destroy_window_with_children[] = {
8260     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8261     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8262     { 0x0090, sent|optional },
8263     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8264     { 0x0090, sent|optional },
8265     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8266     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8267     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8268     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8269     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8270     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8271     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8272     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8273     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8274     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8275     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8276     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8277     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8278     { 0 }
8279 };
8280
8281 static void test_DestroyWindow(void)
8282 {
8283     BOOL ret;
8284     HWND parent, child1, child2, child3, child4, test;
8285     UINT_PTR child_id = WND_CHILD_ID + 1;
8286
8287     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8288                              100, 100, 200, 200, 0, 0, 0, NULL);
8289     assert(parent != 0);
8290     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8291                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8292     assert(child1 != 0);
8293     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8294                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8295     assert(child2 != 0);
8296     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8297                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8298     assert(child3 != 0);
8299     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8300                              0, 0, 50, 50, parent, 0, 0, NULL);
8301     assert(child4 != 0);
8302
8303     /* test owner/parent of child2 */
8304     test = GetParent(child2);
8305     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8306     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8307     if(pGetAncestor) {
8308         test = pGetAncestor(child2, GA_PARENT);
8309         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8310     }
8311     test = GetWindow(child2, GW_OWNER);
8312     ok(!test, "wrong owner %p\n", test);
8313
8314     test = SetParent(child2, parent);
8315     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8316
8317     /* test owner/parent of the parent */
8318     test = GetParent(parent);
8319     ok(!test, "wrong parent %p\n", test);
8320     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8321     if(pGetAncestor) {
8322         test = pGetAncestor(parent, GA_PARENT);
8323         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8324     }
8325     test = GetWindow(parent, GW_OWNER);
8326     ok(!test, "wrong owner %p\n", test);
8327
8328     /* test owner/parent of child1 */
8329     test = GetParent(child1);
8330     ok(test == parent, "wrong parent %p\n", test);
8331     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8332     if(pGetAncestor) {
8333         test = pGetAncestor(child1, GA_PARENT);
8334         ok(test == parent, "wrong parent %p\n", test);
8335     }
8336     test = GetWindow(child1, GW_OWNER);
8337     ok(!test, "wrong owner %p\n", test);
8338
8339     /* test owner/parent of child2 */
8340     test = GetParent(child2);
8341     ok(test == parent, "wrong parent %p\n", test);
8342     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8343     if(pGetAncestor) {
8344         test = pGetAncestor(child2, GA_PARENT);
8345         ok(test == parent, "wrong parent %p\n", test);
8346     }
8347     test = GetWindow(child2, GW_OWNER);
8348     ok(!test, "wrong owner %p\n", test);
8349
8350     /* test owner/parent of child3 */
8351     test = GetParent(child3);
8352     ok(test == child1, "wrong parent %p\n", test);
8353     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8354     if(pGetAncestor) {
8355         test = pGetAncestor(child3, GA_PARENT);
8356         ok(test == child1, "wrong parent %p\n", test);
8357     }
8358     test = GetWindow(child3, GW_OWNER);
8359     ok(!test, "wrong owner %p\n", test);
8360
8361     /* test owner/parent of child4 */
8362     test = GetParent(child4);
8363     ok(test == parent, "wrong parent %p\n", test);
8364     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8365     if(pGetAncestor) {
8366         test = pGetAncestor(child4, GA_PARENT);
8367         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8368     }
8369     test = GetWindow(child4, GW_OWNER);
8370     ok(test == parent, "wrong owner %p\n", test);
8371
8372     flush_sequence();
8373
8374     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8375            parent, child1, child2, child3, child4);
8376
8377     SetCapture(child4);
8378     test = GetCapture();
8379     ok(test == child4, "wrong capture window %p\n", test);
8380
8381     test_DestroyWindow_flag = TRUE;
8382     ret = DestroyWindow(parent);
8383     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8384     test_DestroyWindow_flag = FALSE;
8385     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8386
8387     ok(!IsWindow(parent), "parent still exists\n");
8388     ok(!IsWindow(child1), "child1 still exists\n");
8389     ok(!IsWindow(child2), "child2 still exists\n");
8390     ok(!IsWindow(child3), "child3 still exists\n");
8391     ok(!IsWindow(child4), "child4 still exists\n");
8392
8393     test = GetCapture();
8394     ok(!test, "wrong capture window %p\n", test);
8395 }
8396
8397
8398 static const struct message WmDispatchPaint[] = {
8399     { WM_NCPAINT, sent },
8400     { WM_GETTEXT, sent|defwinproc|optional },
8401     { WM_GETTEXT, sent|defwinproc|optional },
8402     { WM_ERASEBKGND, sent },
8403     { 0 }
8404 };
8405
8406 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8407 {
8408     if (message == WM_PAINT) return 0;
8409     return MsgCheckProcA( hwnd, message, wParam, lParam );
8410 }
8411
8412 static void test_DispatchMessage(void)
8413 {
8414     RECT rect;
8415     MSG msg;
8416     int count;
8417     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8418                                100, 100, 200, 200, 0, 0, 0, NULL);
8419     ShowWindow( hwnd, SW_SHOW );
8420     UpdateWindow( hwnd );
8421     flush_events();
8422     flush_sequence();
8423     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8424
8425     SetRect( &rect, -5, -5, 5, 5 );
8426     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8427     count = 0;
8428     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8429     {
8430         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8431         else
8432         {
8433             flush_sequence();
8434             DispatchMessage( &msg );
8435             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8436             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8437             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8438             if (++count > 10) break;
8439         }
8440     }
8441     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8442
8443     trace("now without DispatchMessage\n");
8444     flush_sequence();
8445     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8446     count = 0;
8447     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8448     {
8449         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8450         else
8451         {
8452             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8453             flush_sequence();
8454             /* this will send WM_NCCPAINT just like DispatchMessage does */
8455             GetUpdateRgn( hwnd, hrgn, TRUE );
8456             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8457             DeleteObject( hrgn );
8458             GetClientRect( hwnd, &rect );
8459             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8460             ok( !count, "Got multiple WM_PAINTs\n" );
8461             if (++count > 10) break;
8462         }
8463     }
8464     DestroyWindow(hwnd);
8465 }
8466
8467
8468 static const struct message WmUser[] = {
8469     { WM_USER, sent },
8470     { 0 }
8471 };
8472
8473 struct sendmsg_info
8474 {
8475     HWND  hwnd;
8476     DWORD timeout;
8477     DWORD ret;
8478 };
8479
8480 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8481 {
8482     struct sendmsg_info *info = arg;
8483     SetLastError( 0xdeadbeef );
8484     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8485     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8486                         broken(GetLastError() == 0),  /* win9x */
8487                         "unexpected error %d\n", GetLastError());
8488     return 0;
8489 }
8490
8491 static void wait_for_thread( HANDLE thread )
8492 {
8493     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8494     {
8495         MSG msg;
8496         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8497     }
8498 }
8499
8500 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8501 {
8502     if (message == WM_USER) Sleep(200);
8503     return MsgCheckProcA( hwnd, message, wParam, lParam );
8504 }
8505
8506 static void test_SendMessageTimeout(void)
8507 {
8508     HANDLE thread;
8509     struct sendmsg_info info;
8510     DWORD tid;
8511     BOOL is_win9x;
8512
8513     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8514                                100, 100, 200, 200, 0, 0, 0, NULL);
8515     flush_events();
8516     flush_sequence();
8517
8518     info.timeout = 1000;
8519     info.ret = 0xdeadbeef;
8520     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8521     wait_for_thread( thread );
8522     CloseHandle( thread );
8523     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8524     ok_sequence( WmUser, "WmUser", FALSE );
8525
8526     info.timeout = 1;
8527     info.ret = 0xdeadbeef;
8528     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8529     Sleep(100);  /* SendMessageTimeout should time out here */
8530     wait_for_thread( thread );
8531     CloseHandle( thread );
8532     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8533     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8534
8535     /* 0 means infinite timeout (but not on win9x) */
8536     info.timeout = 0;
8537     info.ret = 0xdeadbeef;
8538     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8539     Sleep(100);
8540     wait_for_thread( thread );
8541     CloseHandle( thread );
8542     is_win9x = !info.ret;
8543     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8544     else ok_sequence( WmUser, "WmUser", FALSE );
8545
8546     /* timeout is treated as signed despite the prototype (but not on win9x) */
8547     info.timeout = 0x7fffffff;
8548     info.ret = 0xdeadbeef;
8549     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8550     Sleep(100);
8551     wait_for_thread( thread );
8552     CloseHandle( thread );
8553     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8554     ok_sequence( WmUser, "WmUser", FALSE );
8555
8556     info.timeout = 0x80000000;
8557     info.ret = 0xdeadbeef;
8558     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8559     Sleep(100);
8560     wait_for_thread( thread );
8561     CloseHandle( thread );
8562     if (is_win9x)
8563     {
8564         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8565         ok_sequence( WmUser, "WmUser", FALSE );
8566     }
8567     else
8568     {
8569         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8570         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8571     }
8572
8573     /* now check for timeout during message processing */
8574     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8575     info.timeout = 100;
8576     info.ret = 0xdeadbeef;
8577     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8578     wait_for_thread( thread );
8579     CloseHandle( thread );
8580     /* we should time out but still get the message */
8581     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8582     ok_sequence( WmUser, "WmUser", FALSE );
8583
8584     DestroyWindow( info.hwnd );
8585 }
8586
8587
8588 /****************** edit message test *************************/
8589 #define ID_EDIT 0x1234
8590 static const struct message sl_edit_setfocus[] =
8591 {
8592     { HCBT_SETFOCUS, hook },
8593     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8594     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8595     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8596     { WM_SETFOCUS, sent|wparam, 0 },
8597     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8598     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8599     { WM_CTLCOLOREDIT, sent|parent },
8600     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8601     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8602     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8603     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8604     { 0 }
8605 };
8606 static const struct message ml_edit_setfocus[] =
8607 {
8608     { HCBT_SETFOCUS, hook },
8609     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8610     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8611     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8612     { WM_SETFOCUS, sent|wparam, 0 },
8613     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8614     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8615     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8616     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8617     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8618     { 0 }
8619 };
8620 static const struct message sl_edit_killfocus[] =
8621 {
8622     { HCBT_SETFOCUS, hook },
8623     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8624     { WM_KILLFOCUS, sent|wparam, 0 },
8625     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8626     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8627     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8628     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8629     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8630     { 0 }
8631 };
8632 static const struct message sl_edit_lbutton_dblclk[] =
8633 {
8634     { WM_LBUTTONDBLCLK, sent },
8635     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8636     { 0 }
8637 };
8638 static const struct message sl_edit_lbutton_down[] =
8639 {
8640     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8641     { HCBT_SETFOCUS, hook },
8642     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8643     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8644     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8645     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8646     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8647     { WM_CTLCOLOREDIT, sent|parent },
8648     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8649     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8650     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8651     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8652     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8653     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8654     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8655     { WM_CTLCOLOREDIT, sent|parent|optional },
8656     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8657     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8658     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8659     { 0 }
8660 };
8661 static const struct message ml_edit_lbutton_down[] =
8662 {
8663     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8664     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8665     { HCBT_SETFOCUS, hook },
8666     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8667     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8668     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8669     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8670     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8671     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8672     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8673     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8674     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8675     { 0 }
8676 };
8677 static const struct message sl_edit_lbutton_up[] =
8678 {
8679     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8680     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8681     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8682     { WM_CAPTURECHANGED, sent|defwinproc },
8683     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8684     { 0 }
8685 };
8686 static const struct message ml_edit_lbutton_up[] =
8687 {
8688     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8689     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8690     { WM_CAPTURECHANGED, sent|defwinproc },
8691     { 0 }
8692 };
8693
8694 static WNDPROC old_edit_proc;
8695
8696 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8697 {
8698     static long defwndproc_counter = 0;
8699     LRESULT ret;
8700     struct recvd_message msg;
8701
8702     if (message == WM_GETICON || message == WM_GETOBJECT) return 0;  /* ignore them */
8703
8704     msg.hwnd = hwnd;
8705     msg.message = message;
8706     msg.flags = sent|wparam|lparam;
8707     if (defwndproc_counter) msg.flags |= defwinproc;
8708     msg.wParam = wParam;
8709     msg.lParam = lParam;
8710     msg.descr = "edit";
8711     add_message(&msg);
8712
8713     defwndproc_counter++;
8714     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8715     defwndproc_counter--;
8716
8717     return ret;
8718 }
8719
8720 static void subclass_edit(void)
8721 {
8722     WNDCLASSA cls;
8723
8724     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8725
8726     old_edit_proc = cls.lpfnWndProc;
8727
8728     cls.hInstance = GetModuleHandle(0);
8729     cls.lpfnWndProc = edit_hook_proc;
8730     cls.lpszClassName = "my_edit_class";
8731     UnregisterClass(cls.lpszClassName, cls.hInstance);
8732     if (!RegisterClassA(&cls)) assert(0);
8733 }
8734
8735 static void test_edit_messages(void)
8736 {
8737     HWND hwnd, parent;
8738     DWORD dlg_code;
8739
8740     subclass_edit();
8741     log_all_parent_messages++;
8742
8743     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8744                              100, 100, 200, 200, 0, 0, 0, NULL);
8745     ok (parent != 0, "Failed to create parent window\n");
8746
8747     /* test single line edit */
8748     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8749                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8750     ok(hwnd != 0, "Failed to create edit window\n");
8751
8752     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8753     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8754
8755     ShowWindow(hwnd, SW_SHOW);
8756     UpdateWindow(hwnd);
8757     SetFocus(0);
8758     flush_sequence();
8759
8760     SetFocus(hwnd);
8761     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8762
8763     SetFocus(0);
8764     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8765
8766     SetFocus(0);
8767     ReleaseCapture();
8768     flush_sequence();
8769
8770     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8771     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8772
8773     SetFocus(0);
8774     ReleaseCapture();
8775     flush_sequence();
8776
8777     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8778     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8779
8780     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8781     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8782
8783     DestroyWindow(hwnd);
8784
8785     /* test multiline edit */
8786     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8787                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8788     ok(hwnd != 0, "Failed to create edit window\n");
8789
8790     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8791     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8792        "wrong dlg_code %08x\n", dlg_code);
8793
8794     ShowWindow(hwnd, SW_SHOW);
8795     UpdateWindow(hwnd);
8796     SetFocus(0);
8797     flush_sequence();
8798
8799     SetFocus(hwnd);
8800     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8801
8802     SetFocus(0);
8803     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8804
8805     SetFocus(0);
8806     ReleaseCapture();
8807     flush_sequence();
8808
8809     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8810     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8811
8812     SetFocus(0);
8813     ReleaseCapture();
8814     flush_sequence();
8815
8816     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8817     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8818
8819     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8820     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8821
8822     DestroyWindow(hwnd);
8823     DestroyWindow(parent);
8824
8825     log_all_parent_messages--;
8826 }
8827
8828 /**************************** End of Edit test ******************************/
8829
8830 static const struct message WmKeyDownSkippedSeq[] =
8831 {
8832     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8833     { 0 }
8834 };
8835 static const struct message WmKeyDownWasDownSkippedSeq[] =
8836 {
8837     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
8838     { 0 }
8839 };
8840 static const struct message WmKeyUpSkippedSeq[] =
8841 {
8842     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8843     { 0 }
8844 };
8845 static const struct message WmUserKeyUpSkippedSeq[] =
8846 {
8847     { WM_USER, sent },
8848     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8849     { 0 }
8850 };
8851
8852 #define EV_STOP 0
8853 #define EV_SENDMSG 1
8854 #define EV_ACK 2
8855
8856 struct peekmsg_info
8857 {
8858     HWND  hwnd;
8859     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8860 };
8861
8862 static DWORD CALLBACK send_msg_thread_2(void *param)
8863 {
8864     DWORD ret;
8865     struct peekmsg_info *info = param;
8866
8867     trace("thread: looping\n");
8868     SetEvent(info->hevent[EV_ACK]);
8869
8870     while (1)
8871     {
8872         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8873
8874         switch (ret)
8875         {
8876         case WAIT_OBJECT_0 + EV_STOP:
8877             trace("thread: exiting\n");
8878             return 0;
8879
8880         case WAIT_OBJECT_0 + EV_SENDMSG:
8881             trace("thread: sending message\n");
8882             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
8883                 "SendNotifyMessageA failed error %u\n", GetLastError());
8884             SetEvent(info->hevent[EV_ACK]);
8885             break;
8886
8887         default:
8888             trace("unexpected return: %04x\n", ret);
8889             assert(0);
8890             break;
8891         }
8892     }
8893     return 0;
8894 }
8895
8896 static void test_PeekMessage(void)
8897 {
8898     MSG msg;
8899     HANDLE hthread;
8900     DWORD tid, qstatus;
8901     UINT qs_all_input = QS_ALLINPUT;
8902     UINT qs_input = QS_INPUT;
8903     BOOL ret;
8904     struct peekmsg_info info;
8905
8906     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8907                               100, 100, 200, 200, 0, 0, 0, NULL);
8908     assert(info.hwnd);
8909     ShowWindow(info.hwnd, SW_SHOW);
8910     UpdateWindow(info.hwnd);
8911     SetFocus(info.hwnd);
8912
8913     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
8914     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8915     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8916
8917     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8918     WaitForSingleObject(info.hevent[EV_ACK], 10000);
8919
8920     flush_events();
8921     flush_sequence();
8922
8923     SetLastError(0xdeadbeef);
8924     qstatus = GetQueueStatus(qs_all_input);
8925     if (GetLastError() == ERROR_INVALID_FLAGS)
8926     {
8927         trace("QS_RAWINPUT not supported on this platform\n");
8928         qs_all_input &= ~QS_RAWINPUT;
8929         qs_input &= ~QS_RAWINPUT;
8930     }
8931     if (qstatus & QS_POSTMESSAGE)
8932     {
8933         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
8934         qstatus = GetQueueStatus(qs_all_input);
8935     }
8936     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8937
8938     trace("signalling to send message\n");
8939     SetEvent(info.hevent[EV_SENDMSG]);
8940     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8941
8942     /* pass invalid QS_xxxx flags */
8943     SetLastError(0xdeadbeef);
8944     qstatus = GetQueueStatus(0xffffffff);
8945     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
8946     if (!qstatus)
8947     {
8948         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8949         qstatus = GetQueueStatus(qs_all_input);
8950     }
8951     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8952        "wrong qstatus %08x\n", qstatus);
8953
8954     msg.message = 0;
8955     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8956     ok(!ret,
8957        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8958         msg.message);
8959     ok_sequence(WmUser, "WmUser", FALSE);
8960
8961     qstatus = GetQueueStatus(qs_all_input);
8962     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8963
8964     keybd_event('N', 0, 0, 0);
8965     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8966     qstatus = GetQueueStatus(qs_all_input);
8967     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
8968     {
8969         skip( "queuing key events not supported\n" );
8970         goto done;
8971     }
8972     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8973        "wrong qstatus %08x\n", qstatus);
8974
8975     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8976     qstatus = GetQueueStatus(qs_all_input);
8977     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8978        "wrong qstatus %08x\n", qstatus);
8979
8980     InvalidateRect(info.hwnd, NULL, FALSE);
8981     qstatus = GetQueueStatus(qs_all_input);
8982     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8983        "wrong qstatus %08x\n", qstatus);
8984
8985     trace("signalling to send message\n");
8986     SetEvent(info.hevent[EV_SENDMSG]);
8987     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8988
8989     qstatus = GetQueueStatus(qs_all_input);
8990     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8991        "wrong qstatus %08x\n", qstatus);
8992
8993     msg.message = 0;
8994     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8995     if (ret && msg.message == WM_CHAR)
8996     {
8997         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
8998         goto done;
8999     }
9000     ok(!ret,
9001        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9002         msg.message);
9003     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9004     {
9005         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9006         goto done;
9007     }
9008     ok_sequence(WmUser, "WmUser", FALSE);
9009
9010     qstatus = GetQueueStatus(qs_all_input);
9011     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9012        "wrong qstatus %08x\n", qstatus);
9013
9014     trace("signalling to send message\n");
9015     SetEvent(info.hevent[EV_SENDMSG]);
9016     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9017
9018     qstatus = GetQueueStatus(qs_all_input);
9019     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9020        "wrong qstatus %08x\n", qstatus);
9021
9022     msg.message = 0;
9023     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9024     ok(!ret,
9025        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9026         msg.message);
9027     ok_sequence(WmUser, "WmUser", FALSE);
9028
9029     qstatus = GetQueueStatus(qs_all_input);
9030     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9031        "wrong qstatus %08x\n", qstatus);
9032
9033     msg.message = 0;
9034     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9035     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9036        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9037        ret, msg.message, msg.wParam);
9038     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9039
9040     qstatus = GetQueueStatus(qs_all_input);
9041     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9042        "wrong qstatus %08x\n", qstatus);
9043
9044     msg.message = 0;
9045     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9046     ok(!ret,
9047        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9048         msg.message);
9049     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9050
9051     qstatus = GetQueueStatus(qs_all_input);
9052     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9053        "wrong qstatus %08x\n", qstatus);
9054
9055     msg.message = 0;
9056     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9057     ok(ret && msg.message == WM_PAINT,
9058        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9059     DispatchMessageA(&msg);
9060     ok_sequence(WmPaint, "WmPaint", FALSE);
9061
9062     qstatus = GetQueueStatus(qs_all_input);
9063     ok(qstatus == MAKELONG(0, QS_KEY),
9064        "wrong qstatus %08x\n", qstatus);
9065
9066     msg.message = 0;
9067     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9068     ok(!ret,
9069        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9070         msg.message);
9071     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9072
9073     qstatus = GetQueueStatus(qs_all_input);
9074     ok(qstatus == MAKELONG(0, QS_KEY),
9075        "wrong qstatus %08x\n", qstatus);
9076
9077     trace("signalling to send message\n");
9078     SetEvent(info.hevent[EV_SENDMSG]);
9079     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9080
9081     qstatus = GetQueueStatus(qs_all_input);
9082     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9083        "wrong qstatus %08x\n", qstatus);
9084
9085     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9086
9087     qstatus = GetQueueStatus(qs_all_input);
9088     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9089        "wrong qstatus %08x\n", qstatus);
9090
9091     msg.message = 0;
9092     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9093     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9094        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9095        ret, msg.message, msg.wParam);
9096     ok_sequence(WmUser, "WmUser", FALSE);
9097
9098     qstatus = GetQueueStatus(qs_all_input);
9099     ok(qstatus == MAKELONG(0, QS_KEY),
9100        "wrong qstatus %08x\n", qstatus);
9101
9102     msg.message = 0;
9103     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9104     ok(!ret,
9105        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9106         msg.message);
9107     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9108
9109     qstatus = GetQueueStatus(qs_all_input);
9110     ok(qstatus == MAKELONG(0, QS_KEY),
9111        "wrong qstatus %08x\n", qstatus);
9112
9113     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9114
9115     qstatus = GetQueueStatus(qs_all_input);
9116     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9117        "wrong qstatus %08x\n", qstatus);
9118
9119     trace("signalling to send message\n");
9120     SetEvent(info.hevent[EV_SENDMSG]);
9121     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9122
9123     qstatus = GetQueueStatus(qs_all_input);
9124     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9125        "wrong qstatus %08x\n", qstatus);
9126
9127     msg.message = 0;
9128     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9129     ok(!ret,
9130        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9131         msg.message);
9132     ok_sequence(WmUser, "WmUser", FALSE);
9133
9134     qstatus = GetQueueStatus(qs_all_input);
9135     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9136        "wrong qstatus %08x\n", qstatus);
9137
9138     msg.message = 0;
9139     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9140         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9141     else /* workaround for a missing QS_RAWINPUT support */
9142         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9143     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9144        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9145        ret, msg.message, msg.wParam);
9146     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9147
9148     qstatus = GetQueueStatus(qs_all_input);
9149     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9150        "wrong qstatus %08x\n", qstatus);
9151
9152     msg.message = 0;
9153     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9154         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9155     else /* workaround for a missing QS_RAWINPUT support */
9156         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9157     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9158        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9159        ret, msg.message, msg.wParam);
9160     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9161
9162     qstatus = GetQueueStatus(qs_all_input);
9163     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9164        "wrong qstatus %08x\n", qstatus);
9165
9166     msg.message = 0;
9167     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9168     ok(!ret,
9169        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9170         msg.message);
9171     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9172
9173     qstatus = GetQueueStatus(qs_all_input);
9174     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9175        "wrong qstatus %08x\n", qstatus);
9176
9177     msg.message = 0;
9178     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9179     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9180        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9181        ret, msg.message, msg.wParam);
9182     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9183
9184     qstatus = GetQueueStatus(qs_all_input);
9185     ok(qstatus == 0,
9186        "wrong qstatus %08x\n", qstatus);
9187
9188     msg.message = 0;
9189     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9190     ok(!ret,
9191        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9192         msg.message);
9193     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9194
9195     qstatus = GetQueueStatus(qs_all_input);
9196     ok(qstatus == 0,
9197        "wrong qstatus %08x\n", qstatus);
9198
9199     /* test whether presence of the quit flag in the queue affects
9200      * the queue state
9201      */
9202     PostQuitMessage(0x1234abcd);
9203
9204     qstatus = GetQueueStatus(qs_all_input);
9205     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9206        "wrong qstatus %08x\n", qstatus);
9207
9208     PostMessageA(info.hwnd, WM_USER, 0, 0);
9209
9210     qstatus = GetQueueStatus(qs_all_input);
9211     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9212        "wrong qstatus %08x\n", qstatus);
9213
9214     msg.message = 0;
9215     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9216     ok(ret && msg.message == WM_USER,
9217        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9218     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9219
9220     qstatus = GetQueueStatus(qs_all_input);
9221     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9222        "wrong qstatus %08x\n", qstatus);
9223
9224     msg.message = 0;
9225     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9226     ok(ret && msg.message == WM_QUIT,
9227        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9228     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9229     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9230     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9231
9232     qstatus = GetQueueStatus(qs_all_input);
9233 todo_wine {
9234     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9235        "wrong qstatus %08x\n", qstatus);
9236 }
9237
9238     msg.message = 0;
9239     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9240     ok(!ret,
9241        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9242         msg.message);
9243     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9244
9245     qstatus = GetQueueStatus(qs_all_input);
9246     ok(qstatus == 0,
9247        "wrong qstatus %08x\n", qstatus);
9248
9249     /* some GetMessage tests */
9250
9251     keybd_event('N', 0, 0, 0);
9252     qstatus = GetQueueStatus(qs_all_input);
9253     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9254
9255     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9256     qstatus = GetQueueStatus(qs_all_input);
9257     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9258
9259     if (qstatus)
9260     {
9261         ret = GetMessageA( &msg, 0, 0, 0 );
9262         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9263            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9264            ret, msg.message, msg.wParam);
9265         qstatus = GetQueueStatus(qs_all_input);
9266         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9267     }
9268
9269     if (qstatus)
9270     {
9271         ret = GetMessageA( &msg, 0, 0, 0 );
9272         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9273            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9274            ret, msg.message, msg.wParam);
9275         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9276         qstatus = GetQueueStatus(qs_all_input);
9277         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9278     }
9279
9280     keybd_event('N', 0, 0, 0);
9281     qstatus = GetQueueStatus(qs_all_input);
9282     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9283
9284     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9285     qstatus = GetQueueStatus(qs_all_input);
9286     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9287
9288     if (qstatus & (QS_KEY << 16))
9289     {
9290         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9291         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9292            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9293            ret, msg.message, msg.wParam);
9294         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9295         qstatus = GetQueueStatus(qs_all_input);
9296         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9297     }
9298
9299     if (qstatus)
9300     {
9301         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9302         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9303            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9304            ret, msg.message, msg.wParam);
9305         qstatus = GetQueueStatus(qs_all_input);
9306         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9307     }
9308
9309     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9310     qstatus = GetQueueStatus(qs_all_input);
9311     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9312
9313     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9314     qstatus = GetQueueStatus(qs_all_input);
9315     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9316
9317     trace("signalling to send message\n");
9318     SetEvent(info.hevent[EV_SENDMSG]);
9319     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9320     qstatus = GetQueueStatus(qs_all_input);
9321     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9322        "wrong qstatus %08x\n", qstatus);
9323
9324     if (qstatus & (QS_KEY << 16))
9325     {
9326         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9327         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9328            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9329            ret, msg.message, msg.wParam);
9330         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9331         qstatus = GetQueueStatus(qs_all_input);
9332         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9333     }
9334
9335     if (qstatus)
9336     {
9337         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9338         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9339            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9340            ret, msg.message, msg.wParam);
9341         qstatus = GetQueueStatus(qs_all_input);
9342         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9343     }
9344 done:
9345     trace("signalling to exit\n");
9346     SetEvent(info.hevent[EV_STOP]);
9347
9348     WaitForSingleObject(hthread, INFINITE);
9349
9350     CloseHandle(hthread);
9351     CloseHandle(info.hevent[0]);
9352     CloseHandle(info.hevent[1]);
9353     CloseHandle(info.hevent[2]);
9354
9355     DestroyWindow(info.hwnd);
9356 }
9357
9358 static void wait_move_event(HWND hwnd, int x, int y)
9359 {
9360     MSG msg;
9361     DWORD time;
9362     BOOL  ret;
9363     int go = 0;
9364
9365     time = GetTickCount();
9366     while (GetTickCount() - time < 200 && !go) {
9367         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9368         go  = ret && msg.pt.x > x && msg.pt.y > y;
9369         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9370     }
9371 }
9372
9373 #define STEP 5
9374 static void test_PeekMessage2(void)
9375 {
9376     HWND hwnd;
9377     BOOL ret;
9378     MSG msg;
9379     UINT message;
9380     DWORD time1, time2, time3;
9381     int x1, y1, x2, y2, x3, y3;
9382     POINT pos;
9383
9384     time1 = time2 = time3 = 0;
9385     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9386
9387     /* Initialise window and make sure it is ready for events */
9388     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9389                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9390     assert(hwnd);
9391     trace("Window for test_PeekMessage2 %p\n", hwnd);
9392     ShowWindow(hwnd, SW_SHOW);
9393     UpdateWindow(hwnd);
9394     SetFocus(hwnd);
9395     GetCursorPos(&pos);
9396     SetCursorPos(100, 100);
9397     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9398     flush_events();
9399
9400     /* Do initial mousemove, wait until we can see it
9401        and then do our test peek with PM_NOREMOVE. */
9402     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9403     wait_move_event(hwnd, 100-STEP, 100-STEP);
9404
9405     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9406     ok(ret, "no message available\n");
9407     if (ret) {
9408         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9409         message = msg.message;
9410         time1 = msg.time;
9411         x1 = msg.pt.x;
9412         y1 = msg.pt.y;
9413         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9414     }
9415
9416     /* Allow time to advance a bit, and then simulate the user moving their
9417      * mouse around. After that we peek again with PM_NOREMOVE.
9418      * Although the previous mousemove message was never removed, the
9419      * mousemove we now peek should reflect the recent mouse movements
9420      * because the input queue will merge the move events. */
9421     Sleep(100);
9422     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9423     wait_move_event(hwnd, x1, y1);
9424
9425     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9426     ok(ret, "no message available\n");
9427     if (ret) {
9428         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9429         message = msg.message;
9430         time2 = msg.time;
9431         x2 = msg.pt.x;
9432         y2 = msg.pt.y;
9433         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9434         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9435         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9436     }
9437
9438     /* Have another go, to drive the point home */
9439     Sleep(100);
9440     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9441     wait_move_event(hwnd, x2, y2);
9442
9443     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9444     ok(ret, "no message available\n");
9445     if (ret) {
9446         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9447         message = msg.message;
9448         time3 = msg.time;
9449         x3 = msg.pt.x;
9450         y3 = msg.pt.y;
9451         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9452         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9453         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9454     }
9455
9456     DestroyWindow(hwnd);
9457     SetCursorPos(pos.x, pos.y);
9458     flush_events();
9459 }
9460
9461 static void test_quit_message(void)
9462 {
9463     MSG msg;
9464     BOOL ret;
9465
9466     /* test using PostQuitMessage */
9467     flush_events();
9468     PostQuitMessage(0xbeef);
9469
9470     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9471     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9472     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9473     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9474
9475     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9476     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9477
9478     ret = GetMessage(&msg, NULL, 0, 0);
9479     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9480     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9481
9482     /* note: WM_QUIT message received after WM_USER message */
9483     ret = GetMessage(&msg, NULL, 0, 0);
9484     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9485     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9486     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9487
9488     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9489     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9490
9491     /* now test with PostThreadMessage - different behaviour! */
9492     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9493
9494     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9495     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9496     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9497     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9498
9499     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9500     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9501
9502     /* note: we receive the WM_QUIT message first this time */
9503     ret = GetMessage(&msg, NULL, 0, 0);
9504     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9505     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9506     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9507
9508     ret = GetMessage(&msg, NULL, 0, 0);
9509     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9510     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9511 }
9512
9513 static const struct message WmMouseHoverSeq[] = {
9514     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9515     { WM_MOUSEACTIVATE, sent|optional },
9516     { WM_TIMER, sent|optional }, /* XP sends it */
9517     { WM_SYSTIMER, sent },
9518     { WM_MOUSEHOVER, sent|wparam, 0 },
9519     { 0 }
9520 };
9521
9522 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9523 {
9524     MSG msg;
9525     DWORD start_ticks, end_ticks;
9526
9527     start_ticks = GetTickCount();
9528     /* add some deviation (50%) to cover not expected delays */
9529     start_ticks += timeout / 2;
9530
9531     do
9532     {
9533         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9534         {
9535             /* Timer proc messages are not dispatched to the window proc,
9536              * and therefore not logged.
9537              */
9538             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9539             {
9540                 struct recvd_message s_msg;
9541
9542                 s_msg.hwnd = msg.hwnd;
9543                 s_msg.message = msg.message;
9544                 s_msg.flags = sent|wparam|lparam;
9545                 s_msg.wParam = msg.wParam;
9546                 s_msg.lParam = msg.lParam;
9547                 s_msg.descr = "msg_loop";
9548                 add_message(&s_msg);
9549             }
9550             DispatchMessage(&msg);
9551         }
9552
9553         end_ticks = GetTickCount();
9554
9555         /* inject WM_MOUSEMOVE to see how it changes tracking */
9556         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9557         {
9558             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9559             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9560
9561             inject_mouse_move = FALSE;
9562         }
9563     } while (start_ticks + timeout >= end_ticks);
9564 }
9565
9566 static void test_TrackMouseEvent(void)
9567 {
9568     TRACKMOUSEEVENT tme;
9569     BOOL ret;
9570     HWND hwnd, hchild;
9571     RECT rc_parent, rc_child;
9572     UINT default_hover_time, hover_width = 0, hover_height = 0;
9573
9574 #define track_hover(track_hwnd, track_hover_time) \
9575     tme.cbSize = sizeof(tme); \
9576     tme.dwFlags = TME_HOVER; \
9577     tme.hwndTrack = track_hwnd; \
9578     tme.dwHoverTime = track_hover_time; \
9579     SetLastError(0xdeadbeef); \
9580     ret = pTrackMouseEvent(&tme); \
9581     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9582
9583 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9584     tme.cbSize = sizeof(tme); \
9585     tme.dwFlags = TME_QUERY; \
9586     tme.hwndTrack = (HWND)0xdeadbeef; \
9587     tme.dwHoverTime = 0xdeadbeef; \
9588     SetLastError(0xdeadbeef); \
9589     ret = pTrackMouseEvent(&tme); \
9590     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9591     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9592     ok(tme.dwFlags == (expected_track_flags), \
9593        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9594     ok(tme.hwndTrack == (expected_track_hwnd), \
9595        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9596     ok(tme.dwHoverTime == (expected_hover_time), \
9597        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9598
9599 #define track_hover_cancel(track_hwnd) \
9600     tme.cbSize = sizeof(tme); \
9601     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9602     tme.hwndTrack = track_hwnd; \
9603     tme.dwHoverTime = 0xdeadbeef; \
9604     SetLastError(0xdeadbeef); \
9605     ret = pTrackMouseEvent(&tme); \
9606     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9607
9608     default_hover_time = 0xdeadbeef;
9609     SetLastError(0xdeadbeef);
9610     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9611     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9612        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9613     if (!ret) default_hover_time = 400;
9614     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9615
9616     SetLastError(0xdeadbeef);
9617     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9618     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9619        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9620     if (!ret) hover_width = 4;
9621     SetLastError(0xdeadbeef);
9622     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9623     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9624        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9625     if (!ret) hover_height = 4;
9626     trace("hover rect is %u x %d\n", hover_width, hover_height);
9627
9628     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9629                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9630                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9631                           NULL, NULL, 0);
9632     assert(hwnd);
9633
9634     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9635                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9636                           50, 50, 200, 200, hwnd,
9637                           NULL, NULL, 0);
9638     assert(hchild);
9639
9640     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9641     flush_events();
9642     flush_sequence();
9643
9644     tme.cbSize = 0;
9645     tme.dwFlags = TME_QUERY;
9646     tme.hwndTrack = (HWND)0xdeadbeef;
9647     tme.dwHoverTime = 0xdeadbeef;
9648     SetLastError(0xdeadbeef);
9649     ret = pTrackMouseEvent(&tme);
9650     ok(!ret, "TrackMouseEvent should fail\n");
9651     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9652        "not expected error %u\n", GetLastError());
9653
9654     tme.cbSize = sizeof(tme);
9655     tme.dwFlags = TME_HOVER;
9656     tme.hwndTrack = (HWND)0xdeadbeef;
9657     tme.dwHoverTime = 0xdeadbeef;
9658     SetLastError(0xdeadbeef);
9659     ret = pTrackMouseEvent(&tme);
9660     ok(!ret, "TrackMouseEvent should fail\n");
9661     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9662        "not expected error %u\n", GetLastError());
9663
9664     tme.cbSize = sizeof(tme);
9665     tme.dwFlags = TME_HOVER | TME_CANCEL;
9666     tme.hwndTrack = (HWND)0xdeadbeef;
9667     tme.dwHoverTime = 0xdeadbeef;
9668     SetLastError(0xdeadbeef);
9669     ret = pTrackMouseEvent(&tme);
9670     ok(!ret, "TrackMouseEvent should fail\n");
9671     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9672        "not expected error %u\n", GetLastError());
9673
9674     GetWindowRect(hwnd, &rc_parent);
9675     GetWindowRect(hchild, &rc_child);
9676     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9677
9678     /* Process messages so that the system updates its internal current
9679      * window and hittest, otherwise TrackMouseEvent calls don't have any
9680      * effect.
9681      */
9682     flush_events();
9683     flush_sequence();
9684
9685     track_query(0, NULL, 0);
9686     track_hover(hchild, 0);
9687     track_query(0, NULL, 0);
9688
9689     flush_events();
9690     flush_sequence();
9691
9692     track_hover(hwnd, 0);
9693     tme.cbSize = sizeof(tme);
9694     tme.dwFlags = TME_QUERY;
9695     tme.hwndTrack = (HWND)0xdeadbeef;
9696     tme.dwHoverTime = 0xdeadbeef;
9697     SetLastError(0xdeadbeef);
9698     ret = pTrackMouseEvent(&tme);
9699     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
9700     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
9701     if (!tme.dwFlags)
9702     {
9703         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
9704         DestroyWindow( hwnd );
9705         return;
9706     }
9707     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
9708     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
9709     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
9710        tme.dwHoverTime, default_hover_time);
9711
9712     pump_msg_loop_timeout(default_hover_time, FALSE);
9713     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9714
9715     track_query(0, NULL, 0);
9716
9717     track_hover(hwnd, HOVER_DEFAULT);
9718     track_query(TME_HOVER, hwnd, default_hover_time);
9719
9720     Sleep(default_hover_time / 2);
9721     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9722     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9723
9724     track_query(TME_HOVER, hwnd, default_hover_time);
9725
9726     pump_msg_loop_timeout(default_hover_time, FALSE);
9727     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9728
9729     track_query(0, NULL, 0);
9730
9731     track_hover(hwnd, HOVER_DEFAULT);
9732     track_query(TME_HOVER, hwnd, default_hover_time);
9733
9734     pump_msg_loop_timeout(default_hover_time, TRUE);
9735     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9736
9737     track_query(0, NULL, 0);
9738
9739     track_hover(hwnd, HOVER_DEFAULT);
9740     track_query(TME_HOVER, hwnd, default_hover_time);
9741     track_hover_cancel(hwnd);
9742
9743     DestroyWindow(hwnd);
9744
9745 #undef track_hover
9746 #undef track_query
9747 #undef track_hover_cancel
9748 }
9749
9750
9751 static const struct message WmSetWindowRgn[] = {
9752     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9753     { WM_NCCALCSIZE, sent|wparam, 1 },
9754     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9755     { WM_GETTEXT, sent|defwinproc|optional },
9756     { WM_ERASEBKGND, sent|optional },
9757     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9758     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9759     { 0 }
9760 };
9761
9762 static const struct message WmSetWindowRgn_no_redraw[] = {
9763     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9764     { WM_NCCALCSIZE, sent|wparam, 1 },
9765     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9766     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9767     { 0 }
9768 };
9769
9770 static const struct message WmSetWindowRgn_clear[] = {
9771     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
9772     { WM_NCCALCSIZE, sent|wparam, 1 },
9773     { WM_NCPAINT, sent|optional },
9774     { WM_GETTEXT, sent|defwinproc|optional },
9775     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9776     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9777     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9778     { WM_NCPAINT, sent|optional },
9779     { WM_GETTEXT, sent|defwinproc|optional },
9780     { WM_ERASEBKGND, sent|optional },
9781     { WM_WINDOWPOSCHANGING, sent|optional },
9782     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9783     { WM_NCPAINT, sent|optional },
9784     { WM_GETTEXT, sent|defwinproc|optional },
9785     { WM_ERASEBKGND, sent|optional },
9786     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9787     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9788     { WM_NCPAINT, sent|optional },
9789     { WM_GETTEXT, sent|defwinproc|optional },
9790     { WM_ERASEBKGND, sent|optional },
9791     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9792     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9793     { 0 }
9794 };
9795
9796 static void test_SetWindowRgn(void)
9797 {
9798     HRGN hrgn;
9799     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9800                                 100, 100, 200, 200, 0, 0, 0, NULL);
9801     ok( hwnd != 0, "Failed to create overlapped window\n" );
9802
9803     ShowWindow( hwnd, SW_SHOW );
9804     UpdateWindow( hwnd );
9805     flush_events();
9806     flush_sequence();
9807
9808     trace("testing SetWindowRgn\n");
9809     hrgn = CreateRectRgn( 0, 0, 150, 150 );
9810     SetWindowRgn( hwnd, hrgn, TRUE );
9811     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9812
9813     hrgn = CreateRectRgn( 30, 30, 160, 160 );
9814     SetWindowRgn( hwnd, hrgn, FALSE );
9815     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9816
9817     hrgn = CreateRectRgn( 0, 0, 180, 180 );
9818     SetWindowRgn( hwnd, hrgn, TRUE );
9819     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9820
9821     SetWindowRgn( hwnd, 0, TRUE );
9822     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9823
9824     DestroyWindow( hwnd );
9825 }
9826
9827 /*************************** ShowWindow() test ******************************/
9828 static const struct message WmShowNormal[] = {
9829     { WM_SHOWWINDOW, sent|wparam, 1 },
9830     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9831     { HCBT_ACTIVATE, hook },
9832     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9833     { HCBT_SETFOCUS, hook },
9834     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9835     { 0 }
9836 };
9837 static const struct message WmShow[] = {
9838     { WM_SHOWWINDOW, sent|wparam, 1 },
9839     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9840     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9841     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9842     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9843     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9844     { 0 }
9845 };
9846 static const struct message WmShowNoActivate_1[] = {
9847     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9848     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9849     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9850     { WM_MOVE, sent|defwinproc|optional },
9851     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9852     { 0 }
9853 };
9854 static const struct message WmShowNoActivate_2[] = {
9855     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9856     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9857     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9858     { WM_MOVE, sent|defwinproc },
9859     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9860     { HCBT_SETFOCUS, hook|optional },
9861     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9862     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9863     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9864     { 0 }
9865 };
9866 static const struct message WmShowNA_1[] = {
9867     { WM_SHOWWINDOW, sent|wparam, 1 },
9868     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9869     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9870     { 0 }
9871 };
9872 static const struct message WmShowNA_2[] = {
9873     { WM_SHOWWINDOW, sent|wparam, 1 },
9874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9875     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9876     { 0 }
9877 };
9878 static const struct message WmRestore_1[] = {
9879     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9880     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9881     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9882     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9883     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9884     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9885     { WM_MOVE, sent|defwinproc },
9886     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9887     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9888     { 0 }
9889 };
9890 static const struct message WmRestore_2[] = {
9891     { WM_SHOWWINDOW, sent|wparam, 1 },
9892     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9893     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9894     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9895     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9896     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9897     { 0 }
9898 };
9899 static const struct message WmRestore_3[] = {
9900     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9901     { WM_GETMINMAXINFO, sent },
9902     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9903     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9904     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9905     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9906     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9907     { WM_MOVE, sent|defwinproc },
9908     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9909     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9910     { 0 }
9911 };
9912 static const struct message WmRestore_4[] = {
9913     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
9914     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9915     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9916     { WM_MOVE, sent|defwinproc|optional },
9917     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
9918     { 0 }
9919 };
9920 static const struct message WmRestore_5[] = {
9921     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9922     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9923     { HCBT_ACTIVATE, hook|optional },
9924     { HCBT_SETFOCUS, hook|optional },
9925     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9926     { WM_MOVE, sent|defwinproc|optional },
9927     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9928     { 0 }
9929 };
9930 static const struct message WmHide_1[] = {
9931     { WM_SHOWWINDOW, sent|wparam, 0 },
9932     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9933     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9934     { HCBT_ACTIVATE, hook|optional },
9935     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9936     { 0 }
9937 };
9938 static const struct message WmHide_2[] = {
9939     { WM_SHOWWINDOW, sent|wparam, 0 },
9940     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9941     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9942     { HCBT_ACTIVATE, hook|optional },
9943     { 0 }
9944 };
9945 static const struct message WmHide_3[] = {
9946     { WM_SHOWWINDOW, sent|wparam, 0 },
9947     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9948     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9949     { HCBT_SETFOCUS, hook|optional },
9950     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9951     { 0 }
9952 };
9953 static const struct message WmShowMinimized_1[] = {
9954     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9955     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9956     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9957     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9958     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9959     { WM_MOVE, sent|defwinproc },
9960     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9961     { 0 }
9962 };
9963 static const struct message WmMinimize_1[] = {
9964     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9965     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9966     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9967     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9968     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9969     { WM_MOVE, sent|defwinproc },
9970     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9971     { 0 }
9972 };
9973 static const struct message WmMinimize_2[] = {
9974     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9975     { HCBT_SETFOCUS, hook|optional },
9976     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9977     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9978     { WM_MOVE, sent|defwinproc },
9979     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9980     { 0 }
9981 };
9982 static const struct message WmMinimize_3[] = {
9983     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9984     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9985     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9986     { WM_MOVE, sent|defwinproc },
9987     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9988     { 0 }
9989 };
9990 static const struct message WmShowMinNoActivate[] = {
9991     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9992     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9993     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9994     { 0 }
9995 };
9996 static const struct message WmMinMax_1[] = {
9997     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9998     { 0 }
9999 };
10000 static const struct message WmMinMax_2[] = {
10001     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10002     { WM_GETMINMAXINFO, sent|optional },
10003     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10004     { HCBT_ACTIVATE, hook|optional },
10005     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10006     { HCBT_SETFOCUS, hook|optional },
10007     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10008     { WM_MOVE, sent|defwinproc|optional },
10009     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10010     { HCBT_SETFOCUS, hook|optional },
10011     { 0 }
10012 };
10013 static const struct message WmMinMax_3[] = {
10014     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10015     { HCBT_SETFOCUS, hook|optional },
10016     { 0 }
10017 };
10018 static const struct message WmMinMax_4[] = {
10019     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10020     { 0 }
10021 };
10022 static const struct message WmShowMaximized_1[] = {
10023     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10024     { WM_GETMINMAXINFO, sent },
10025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10026     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10027     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10028     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10029     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10030     { WM_MOVE, sent|defwinproc },
10031     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10032     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10033     { 0 }
10034 };
10035 static const struct message WmShowMaximized_2[] = {
10036     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10037     { WM_GETMINMAXINFO, sent },
10038     { WM_WINDOWPOSCHANGING, sent|optional },
10039     { HCBT_ACTIVATE, hook|optional },
10040     { WM_WINDOWPOSCHANGED, sent|optional },
10041     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10042     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10043     { WM_WINDOWPOSCHANGING, sent|optional },
10044     { HCBT_SETFOCUS, hook|optional },
10045     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10046     { WM_MOVE, sent|defwinproc },
10047     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10048     { HCBT_SETFOCUS, hook|optional },
10049     { 0 }
10050 };
10051 static const struct message WmShowMaximized_3[] = {
10052     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10053     { WM_GETMINMAXINFO, sent },
10054     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10055     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10056     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10057     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10058     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10059     { WM_MOVE, sent|defwinproc|optional },
10060     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10061     { 0 }
10062 };
10063
10064 static void test_ShowWindow(void)
10065 {
10066     /* ShowWindow commands in random order */
10067     static const struct
10068     {
10069         INT cmd; /* ShowWindow command */
10070         LPARAM ret; /* ShowWindow return value */
10071         DWORD style; /* window style after the command */
10072         const struct message *msg; /* message sequence the command produces */
10073         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10074     } sw[] =
10075     {
10076 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10077 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10078 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10079 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10080 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10081 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10082 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10083 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10084 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10085 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10086 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10087 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10088 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10089 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10090 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10091 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10092 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10093 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10094 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10095 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10096 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10097 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10098 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10099 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10100 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10101 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10102 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10103 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10104 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10105 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10106 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10107 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10108 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10109 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10110 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10111 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10112 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10113 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10114 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10115 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10116 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10117 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE },
10118 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10119 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10120 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10121 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10122 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10123 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10124 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10125 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10126 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10127 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10128 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10129 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10130 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10131 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10132 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10133     };
10134     HWND hwnd;
10135     DWORD style;
10136     LPARAM ret;
10137     INT i;
10138
10139 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10140     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10141                           120, 120, 90, 90,
10142                           0, 0, 0, NULL);
10143     assert(hwnd);
10144
10145     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10146     ok(style == 0, "expected style 0, got %08x\n", style);
10147
10148     flush_events();
10149     flush_sequence();
10150
10151     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10152     {
10153         static const char * const sw_cmd_name[13] =
10154         {
10155             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10156             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10157             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10158             "SW_NORMALNA" /* 0xCC */
10159         };
10160         char comment[64];
10161         INT idx; /* index into the above array of names */
10162
10163         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10164
10165         style = GetWindowLong(hwnd, GWL_STYLE);
10166         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10167         ret = ShowWindow(hwnd, sw[i].cmd);
10168         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10169         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10170         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10171
10172         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10173         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10174
10175         flush_events();
10176         flush_sequence();
10177     }
10178
10179     DestroyWindow(hwnd);
10180 }
10181
10182 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10183 {
10184     struct recvd_message msg;
10185
10186     switch (message)
10187     {
10188     case WM_GETICON:
10189     case WM_GETOBJECT:
10190         return 0;  /* ignore them */
10191     }
10192
10193     msg.hwnd = hwnd;
10194     msg.message = message;
10195     msg.flags = sent|wparam|lparam;
10196     msg.wParam = wParam;
10197     msg.lParam = lParam;
10198     msg.descr = "dialog";
10199     add_message(&msg);
10200
10201     /* calling DefDlgProc leads to a recursion under XP */
10202
10203     switch (message)
10204     {
10205     case WM_INITDIALOG:
10206     case WM_GETDLGCODE:
10207         return 0;
10208     }
10209     return 1;
10210 }
10211
10212 static const struct message WmDefDlgSetFocus_1[] = {
10213     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10214     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10215     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10216     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10217     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10218     { HCBT_SETFOCUS, hook },
10219     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10220     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10221     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10222     { WM_SETFOCUS, sent|wparam, 0 },
10223     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10224     { WM_CTLCOLOREDIT, sent },
10225     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10226     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10227     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10228     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10229     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10230     { 0 }
10231 };
10232 static const struct message WmDefDlgSetFocus_2[] = {
10233     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10234     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10235     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10236     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10237     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10238     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10239     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10240     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10241     { 0 }
10242 };
10243 /* Creation of a dialog */
10244 static const struct message WmCreateDialogParamSeq_1[] = {
10245     { HCBT_CREATEWND, hook },
10246     { WM_NCCREATE, sent },
10247     { WM_NCCALCSIZE, sent|wparam, 0 },
10248     { WM_CREATE, sent },
10249     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10250     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10251     { WM_MOVE, sent },
10252     { WM_SETFONT, sent },
10253     { WM_INITDIALOG, sent },
10254     { WM_CHANGEUISTATE, sent|optional },
10255     { 0 }
10256 };
10257 /* Creation of a dialog */
10258 static const struct message WmCreateDialogParamSeq_2[] = {
10259     { HCBT_CREATEWND, hook },
10260     { WM_NCCREATE, sent },
10261     { WM_NCCALCSIZE, sent|wparam, 0 },
10262     { WM_CREATE, sent },
10263     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10264     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10265     { WM_MOVE, sent },
10266     { WM_CHANGEUISTATE, sent|optional },
10267     { 0 }
10268 };
10269
10270 static void test_dialog_messages(void)
10271 {
10272     WNDCLASS cls;
10273     HWND hdlg, hedit1, hedit2, hfocus;
10274     LRESULT ret;
10275
10276 #define set_selection(hctl, start, end) \
10277     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10278     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10279
10280 #define check_selection(hctl, start, end) \
10281     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10282     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10283
10284     subclass_edit();
10285
10286     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10287                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10288                           0, 0, 100, 100, 0, 0, 0, NULL);
10289     ok(hdlg != 0, "Failed to create custom dialog window\n");
10290
10291     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10292                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10293                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10294     ok(hedit1 != 0, "Failed to create edit control\n");
10295     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10296                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10297                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10298     ok(hedit2 != 0, "Failed to create edit control\n");
10299
10300     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10301     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10302
10303     hfocus = GetFocus();
10304     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10305
10306     SetFocus(hedit2);
10307     hfocus = GetFocus();
10308     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10309
10310     check_selection(hedit1, 0, 0);
10311     check_selection(hedit2, 0, 0);
10312
10313     set_selection(hedit2, 0, -1);
10314     check_selection(hedit2, 0, 3);
10315
10316     SetFocus(0);
10317     hfocus = GetFocus();
10318     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10319
10320     flush_sequence();
10321     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10322     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10323     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10324
10325     hfocus = GetFocus();
10326     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10327
10328     check_selection(hedit1, 0, 5);
10329     check_selection(hedit2, 0, 3);
10330
10331     flush_sequence();
10332     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10333     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10334     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10335
10336     hfocus = GetFocus();
10337     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10338
10339     check_selection(hedit1, 0, 5);
10340     check_selection(hedit2, 0, 3);
10341
10342     EndDialog(hdlg, 0);
10343     DestroyWindow(hedit1);
10344     DestroyWindow(hedit2);
10345     DestroyWindow(hdlg);
10346     flush_sequence();
10347
10348 #undef set_selection
10349 #undef check_selection
10350
10351     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10352     cls.lpszClassName = "MyDialogClass";
10353     cls.hInstance = GetModuleHandle(0);
10354     /* need a cast since a dlgproc is used as a wndproc */
10355     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10356     if (!RegisterClass(&cls)) assert(0);
10357
10358     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10359     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10360     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10361     EndDialog(hdlg, 0);
10362     DestroyWindow(hdlg);
10363     flush_sequence();
10364
10365     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10366     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10367     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10368     EndDialog(hdlg, 0);
10369     DestroyWindow(hdlg);
10370     flush_sequence();
10371
10372     UnregisterClass(cls.lpszClassName, cls.hInstance);
10373 }
10374
10375 static void test_nullCallback(void)
10376 {
10377     HWND hwnd;
10378
10379     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10380                            100, 100, 200, 200, 0, 0, 0, NULL);
10381     ok (hwnd != 0, "Failed to create overlapped window\n");
10382
10383     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10384     flush_events();
10385     DestroyWindow(hwnd);
10386 }
10387
10388 /* SetActiveWindow( 0 ) hwnd visible */
10389 static const struct message SetActiveWindowSeq0[] =
10390 {
10391     { HCBT_ACTIVATE, hook|optional },
10392     { WM_NCACTIVATE, sent|wparam, 0 },
10393     { WM_GETTEXT, sent|defwinproc|optional },
10394     { WM_ACTIVATE, sent|wparam, 0 },
10395     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10396     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10397     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10398     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10399     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10400     { WM_NCACTIVATE, sent|wparam|optional, 1 },
10401     { WM_GETTEXT, sent|defwinproc|optional },
10402     { WM_ACTIVATE, sent|wparam|optional, 1 },
10403     { HCBT_SETFOCUS, hook|optional },
10404     { WM_KILLFOCUS, sent|defwinproc },
10405     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10406     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10407     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10408     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10409     { WM_SETFOCUS, sent|defwinproc|optional },
10410     { WM_GETTEXT, sent|optional },
10411     { 0 }
10412 };
10413 /* SetActiveWindow( hwnd ) hwnd visible */
10414 static const struct message SetActiveWindowSeq1[] =
10415 {
10416     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10417     { 0 }
10418 };
10419 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10420 static const struct message SetActiveWindowSeq2[] =
10421 {
10422     { HCBT_ACTIVATE, hook },
10423     { WM_NCACTIVATE, sent|wparam, 0 },
10424     { WM_GETTEXT, sent|defwinproc|optional },
10425     { WM_ACTIVATE, sent|wparam, 0 },
10426     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10427     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10428     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10429     { WM_NCPAINT, sent|optional },
10430     { WM_GETTEXT, sent|defwinproc|optional },
10431     { WM_ERASEBKGND, sent|optional },
10432     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10433     { WM_NCACTIVATE, sent|wparam, 1 },
10434     { WM_GETTEXT, sent|defwinproc|optional },
10435     { WM_ACTIVATE, sent|wparam, 1 },
10436     { HCBT_SETFOCUS, hook },
10437     { WM_KILLFOCUS, sent|defwinproc },
10438     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10439     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10440     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10441     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10442     { WM_SETFOCUS, sent|defwinproc },
10443     { WM_GETTEXT, sent|optional },
10444     { 0 }
10445 };
10446
10447 /* SetActiveWindow( hwnd ) hwnd not visible */
10448 static const struct message SetActiveWindowSeq3[] =
10449 {
10450     { HCBT_ACTIVATE, hook },
10451     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10452     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10453     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10454     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10455     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10456     { WM_ACTIVATEAPP, sent|wparam, 1 },
10457     { WM_ACTIVATEAPP, sent|wparam, 1 },
10458     { WM_NCACTIVATE, sent|wparam, 1 },
10459     { WM_ACTIVATE, sent|wparam, 1 },
10460     { HCBT_SETFOCUS, hook },
10461     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10462     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10463     { WM_SETFOCUS, sent|defwinproc },
10464     { 0 }
10465 };
10466 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10467 static const struct message SetActiveWindowSeq4[] =
10468 {
10469     { HCBT_ACTIVATE, hook },
10470     { WM_NCACTIVATE, sent|wparam, 0 },
10471     { WM_GETTEXT, sent|defwinproc|optional },
10472     { WM_ACTIVATE, sent|wparam, 0 },
10473     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10474     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10475     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10476     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10477     { WM_NCACTIVATE, sent|wparam, 1 },
10478     { WM_GETTEXT, sent|defwinproc|optional },
10479     { WM_ACTIVATE, sent|wparam, 1 },
10480     { HCBT_SETFOCUS, hook },
10481     { WM_KILLFOCUS, sent|defwinproc },
10482     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10483     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10484     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10485     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10486     { WM_SETFOCUS, sent|defwinproc },
10487     { 0 }
10488 };
10489
10490
10491 static void test_SetActiveWindow(void)
10492 {
10493     HWND hwnd, popup, ret;
10494
10495     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10496                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10497                            100, 100, 200, 200, 0, 0, 0, NULL);
10498
10499     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10500                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10501                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10502
10503     ok(hwnd != 0, "Failed to create overlapped window\n");
10504     ok(popup != 0, "Failed to create popup window\n");
10505     SetForegroundWindow( popup );
10506     flush_sequence();
10507
10508     trace("SetActiveWindow(0)\n");
10509     ret = SetActiveWindow(0);
10510     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10511     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", TRUE);
10512     flush_sequence();
10513
10514     trace("SetActiveWindow(hwnd), hwnd visible\n");
10515     ret = SetActiveWindow(hwnd);
10516     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10517     flush_sequence();
10518
10519     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10520     ret = SetActiveWindow(popup);
10521     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10522     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10523     flush_sequence();
10524
10525     ShowWindow(hwnd, SW_HIDE);
10526     ShowWindow(popup, SW_HIDE);
10527     flush_sequence();
10528
10529     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10530     ret = SetActiveWindow(hwnd);
10531     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
10532     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10533     flush_sequence();
10534
10535     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10536     ret = SetActiveWindow(popup);
10537     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10538     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10539     flush_sequence();
10540
10541     trace("done\n");
10542
10543     DestroyWindow(hwnd);
10544 }
10545
10546 static const struct message SetForegroundWindowSeq[] =
10547 {
10548     { WM_NCACTIVATE, sent|wparam, 0 },
10549     { WM_GETTEXT, sent|defwinproc|optional },
10550     { WM_ACTIVATE, sent|wparam, 0 },
10551     { WM_ACTIVATEAPP, sent|wparam, 0 },
10552     { WM_KILLFOCUS, sent },
10553     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10554     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10555     { 0 }
10556 };
10557
10558 static void test_SetForegroundWindow(void)
10559 {
10560     HWND hwnd;
10561
10562     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10563                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10564                            100, 100, 200, 200, 0, 0, 0, NULL);
10565     ok (hwnd != 0, "Failed to create overlapped window\n");
10566     SetForegroundWindow( hwnd );
10567     flush_sequence();
10568
10569     trace("SetForegroundWindow( 0 )\n");
10570     SetForegroundWindow( 0 );
10571     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10572     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10573     SetForegroundWindow( GetDesktopWindow() );
10574     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10575                                         "foreground top level window", FALSE);
10576     trace("done\n");
10577
10578     DestroyWindow(hwnd);
10579 }
10580
10581 static void test_dbcs_wm_char(void)
10582 {
10583     BYTE dbch[2];
10584     WCHAR wch, bad_wch;
10585     HWND hwnd, hwnd2;
10586     MSG msg;
10587     DWORD time;
10588     POINT pt;
10589     DWORD_PTR res;
10590     CPINFOEXA cpinfo;
10591     UINT i, j, k;
10592     struct message wmCharSeq[2];
10593
10594     if (!pGetCPInfoExA)
10595     {
10596         skip("GetCPInfoExA is not available\n");
10597         return;
10598     }
10599
10600     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10601     if (cpinfo.MaxCharSize != 2)
10602     {
10603         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10604         return;
10605     }
10606
10607     dbch[0] = dbch[1] = 0;
10608     wch = 0;
10609     bad_wch = cpinfo.UnicodeDefaultChar;
10610     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10611         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10612             for (k = 128; k <= 255; k++)
10613             {
10614                 char str[2];
10615                 WCHAR wstr[2];
10616                 str[0] = j;
10617                 str[1] = k;
10618                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10619                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10620                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10621                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10622                 {
10623                     dbch[0] = j;
10624                     dbch[1] = k;
10625                     wch = wstr[0];
10626                     break;
10627                 }
10628             }
10629
10630     if (!wch)
10631     {
10632         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10633         return;
10634     }
10635     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10636            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10637
10638     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10639                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10640     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10641                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10642     ok (hwnd != 0, "Failed to create overlapped window\n");
10643     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10644     flush_sequence();
10645
10646     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10647     wmCharSeq[0].message = WM_CHAR;
10648     wmCharSeq[0].flags = sent|wparam;
10649     wmCharSeq[0].wParam = wch;
10650
10651     /* posted message */
10652     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10653     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10654     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10655     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10656     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10657     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10658     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10659
10660     /* posted thread message */
10661     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10662     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10663     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10664     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10665     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10666     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10667     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10668
10669     /* sent message */
10670     flush_sequence();
10671     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10672     ok_sequence( WmEmptySeq, "no messages", FALSE );
10673     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10674     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10675     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10676
10677     /* sent message with timeout */
10678     flush_sequence();
10679     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10680     ok_sequence( WmEmptySeq, "no messages", FALSE );
10681     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10682     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10683     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10684
10685     /* sent message with timeout and callback */
10686     flush_sequence();
10687     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10688     ok_sequence( WmEmptySeq, "no messages", FALSE );
10689     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10690     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10691     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10692
10693     /* sent message with callback */
10694     flush_sequence();
10695     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10696     ok_sequence( WmEmptySeq, "no messages", FALSE );
10697     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10698     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10699     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10700
10701     /* direct window proc call */
10702     flush_sequence();
10703     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10704     ok_sequence( WmEmptySeq, "no messages", FALSE );
10705     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10706     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10707
10708     /* dispatch message */
10709     msg.hwnd = hwnd;
10710     msg.message = WM_CHAR;
10711     msg.wParam = dbch[0];
10712     msg.lParam = 0;
10713     DispatchMessageA( &msg );
10714     ok_sequence( WmEmptySeq, "no messages", FALSE );
10715     msg.wParam = dbch[1];
10716     DispatchMessageA( &msg );
10717     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10718
10719     /* window handle is irrelevant */
10720     flush_sequence();
10721     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10722     ok_sequence( WmEmptySeq, "no messages", FALSE );
10723     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10724     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10725     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10726
10727     /* interleaved post and send */
10728     flush_sequence();
10729     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10730     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10731     ok_sequence( WmEmptySeq, "no messages", FALSE );
10732     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10733     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10734     ok_sequence( WmEmptySeq, "no messages", FALSE );
10735     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10736     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10737     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10738     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10739     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10740     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10741     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10742
10743     /* interleaved sent message and winproc */
10744     flush_sequence();
10745     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10746     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10747     ok_sequence( WmEmptySeq, "no messages", FALSE );
10748     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10749     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10750     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10751     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10752
10753     /* interleaved winproc and dispatch */
10754     msg.hwnd = hwnd;
10755     msg.message = WM_CHAR;
10756     msg.wParam = dbch[0];
10757     msg.lParam = 0;
10758     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10759     DispatchMessageA( &msg );
10760     ok_sequence( WmEmptySeq, "no messages", FALSE );
10761     msg.wParam = dbch[1];
10762     DispatchMessageA( &msg );
10763     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10764     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10765     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10766
10767     /* interleaved sends */
10768     flush_sequence();
10769     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10770     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10771     ok_sequence( WmEmptySeq, "no messages", FALSE );
10772     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10773     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10774     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10775     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10776
10777     /* dbcs WM_CHAR */
10778     flush_sequence();
10779     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10780     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10781     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10782
10783     /* other char messages are not magic */
10784     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10785     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10786     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10787     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10788     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10789     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10790     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10791     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10792     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10793     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10794
10795     /* test retrieving messages */
10796
10797     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10798     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10799     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10800     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10801     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10802     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10803     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10804     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10805     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10806     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10807
10808     /* message filters */
10809     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10810     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10811     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10812     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10813     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10814     /* message id is filtered, hwnd is not */
10815     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10816     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10817     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10818     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10819     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10820     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10821
10822     /* mixing GetMessage and PostMessage */
10823     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10824     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10825     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10826     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10827     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10828     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10829     time = msg.time;
10830     pt = msg.pt;
10831     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
10832     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10833     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10834     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10835     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10836     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10837     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
10838     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 );
10839     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10840
10841     /* without PM_REMOVE */
10842     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10843     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10844     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10845     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10846     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10847     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10848     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10849     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10850     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10851     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10852     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10853     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10854     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10855     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10856     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10857     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10858     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10859     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10860
10861     DestroyWindow(hwnd);
10862 }
10863
10864 #define ID_LISTBOX 0x000f
10865
10866 static const struct message wm_lb_setcursel_0[] =
10867 {
10868     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
10869     { WM_CTLCOLORLISTBOX, sent|parent },
10870     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10871     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10872     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10873     { 0 }
10874 };
10875 static const struct message wm_lb_setcursel_1[] =
10876 {
10877     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
10878     { WM_CTLCOLORLISTBOX, sent|parent },
10879     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
10880     { WM_CTLCOLORLISTBOX, sent|parent },
10881     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
10882     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10883     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10884     { 0 }
10885 };
10886 static const struct message wm_lb_setcursel_2[] =
10887 {
10888     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
10889     { WM_CTLCOLORLISTBOX, sent|parent },
10890     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
10891     { WM_CTLCOLORLISTBOX, sent|parent },
10892     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
10893     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10894     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10895     { 0 }
10896 };
10897 static const struct message wm_lb_click_0[] =
10898 {
10899     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10900     { HCBT_SETFOCUS, hook },
10901     { WM_KILLFOCUS, sent|parent },
10902     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10903     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10904     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10905     { WM_SETFOCUS, sent|defwinproc },
10906
10907     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10908     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10909     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10910     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10911     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10912
10913     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10914     { WM_CTLCOLORLISTBOX, sent|parent },
10915     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10916     { WM_CTLCOLORLISTBOX, sent|parent },
10917     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10918     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
10919
10920     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10921     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10922
10923     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10924     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10925     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
10926     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
10927     { 0 }
10928 };
10929
10930 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
10931
10932 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
10933
10934 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10935 {
10936     static long defwndproc_counter = 0;
10937     LRESULT ret;
10938     struct recvd_message msg;
10939
10940     /* do not log painting messages */
10941     if (message != WM_PAINT &&
10942         message != WM_NCPAINT &&
10943         message != WM_SYNCPAINT &&
10944         message != WM_ERASEBKGND &&
10945         message != WM_NCHITTEST &&
10946         message != WM_GETTEXT &&
10947         message != WM_GETOBJECT &&
10948         message != WM_GETICON &&
10949         message != WM_DEVICECHANGE)
10950     {
10951         msg.hwnd = hwnd;
10952         msg.message = message;
10953         msg.flags = sent|wparam|lparam;
10954         if (defwndproc_counter) msg.flags |= defwinproc;
10955         msg.wParam = wp;
10956         msg.lParam = lp;
10957         msg.descr = "listbox";
10958         add_message(&msg);
10959     }
10960
10961     defwndproc_counter++;
10962     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
10963     defwndproc_counter--;
10964
10965     return ret;
10966 }
10967
10968 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
10969                                int caret_index, int top_index, int line)
10970 {
10971     LRESULT ret;
10972
10973     /* calling an orig proc helps to avoid unnecessary message logging */
10974     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
10975     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
10976     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
10977     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
10978     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
10979     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
10980     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
10981     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
10982 }
10983
10984 static void test_listbox_messages(void)
10985 {
10986     HWND parent, listbox;
10987     LRESULT ret;
10988
10989     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
10990                              100, 100, 200, 200, 0, 0, 0, NULL);
10991     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
10992                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10993                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
10994     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
10995
10996     check_lb_state(listbox, 0, LB_ERR, 0, 0);
10997
10998     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
10999     ok(ret == 0, "expected 0, got %ld\n", ret);
11000     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11001     ok(ret == 1, "expected 1, got %ld\n", ret);
11002     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11003     ok(ret == 2, "expected 2, got %ld\n", ret);
11004
11005     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11006
11007     flush_sequence();
11008
11009     log_all_parent_messages++;
11010
11011     trace("selecting item 0\n");
11012     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11013     ok(ret == 0, "expected 0, got %ld\n", ret);
11014     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11015     check_lb_state(listbox, 3, 0, 0, 0);
11016     flush_sequence();
11017
11018     trace("selecting item 1\n");
11019     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11020     ok(ret == 1, "expected 1, got %ld\n", ret);
11021     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11022     check_lb_state(listbox, 3, 1, 1, 0);
11023
11024     trace("selecting item 2\n");
11025     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11026     ok(ret == 2, "expected 2, got %ld\n", ret);
11027     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11028     check_lb_state(listbox, 3, 2, 2, 0);
11029
11030     trace("clicking on item 0\n");
11031     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11032     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11033     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11034     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11035     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11036     check_lb_state(listbox, 3, 0, 0, 0);
11037     flush_sequence();
11038
11039     log_all_parent_messages--;
11040
11041     DestroyWindow(listbox);
11042     DestroyWindow(parent);
11043 }
11044
11045 /*************************** Menu test ******************************/
11046 static const struct message wm_popup_menu_1[] =
11047 {
11048     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11049     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11050     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11051     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11052     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11053     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11054     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11055     { WM_INITMENU, sent|lparam, 0, 0 },
11056     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11057     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11058     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11059     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11060     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11061     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11062     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11063     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11064     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11065     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11066     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11067     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11068     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11069     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11070     { 0 }
11071 };
11072 static const struct message wm_popup_menu_2[] =
11073 {
11074     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11075     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11076     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11077     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11078     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11079     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11080     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11081     { WM_INITMENU, sent|lparam, 0, 0 },
11082     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11083     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11084     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11085     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11086     { HCBT_CREATEWND, hook },
11087     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11088                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11089     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11090     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11091     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11092     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11093     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11094     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11095     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11096     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11097     { HCBT_DESTROYWND, hook },
11098     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11099     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11100     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11101     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11102     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11103     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11104     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11105     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11106     { 0 }
11107 };
11108 static const struct message wm_popup_menu_3[] =
11109 {
11110     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11111     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11112     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11113     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11114     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11115     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11116     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11117     { WM_INITMENU, sent|lparam, 0, 0 },
11118     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11119     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11120     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11121     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11122     { HCBT_CREATEWND, hook },
11123     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11124                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11125     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11126     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11127     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11128     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11129     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11130     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11131     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11132     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11133     { HCBT_DESTROYWND, hook },
11134     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11135     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11136     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11137     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11138     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11139     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11140     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11141     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11142     { 0 }
11143 };
11144
11145 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11146 {
11147     if (message == WM_ENTERIDLE ||
11148         message == WM_INITMENU ||
11149         message == WM_INITMENUPOPUP ||
11150         message == WM_MENUSELECT ||
11151         message == WM_PARENTNOTIFY ||
11152         message == WM_ENTERMENULOOP ||
11153         message == WM_EXITMENULOOP ||
11154         message == WM_UNINITMENUPOPUP ||
11155         message == WM_KEYDOWN ||
11156         message == WM_KEYUP ||
11157         message == WM_CHAR ||
11158         message == WM_SYSKEYDOWN ||
11159         message == WM_SYSKEYUP ||
11160         message == WM_SYSCHAR ||
11161         message == WM_COMMAND ||
11162         message == WM_MENUCOMMAND)
11163     {
11164         struct recvd_message msg;
11165
11166         msg.hwnd = hwnd;
11167         msg.message = message;
11168         msg.flags = sent|wparam|lparam;
11169         msg.wParam = wp;
11170         msg.lParam = lp;
11171         msg.descr = "parent_menu_proc";
11172         add_message(&msg);
11173     }
11174
11175     return DefWindowProcA(hwnd, message, wp, lp);
11176 }
11177
11178 static void set_menu_style(HMENU hmenu, DWORD style)
11179 {
11180     MENUINFO mi;
11181     BOOL ret;
11182
11183     mi.cbSize = sizeof(mi);
11184     mi.fMask = MIM_STYLE;
11185     mi.dwStyle = style;
11186     SetLastError(0xdeadbeef);
11187     ret = pSetMenuInfo(hmenu, &mi);
11188     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11189 }
11190
11191 static DWORD get_menu_style(HMENU hmenu)
11192 {
11193     MENUINFO mi;
11194     BOOL ret;
11195
11196     mi.cbSize = sizeof(mi);
11197     mi.fMask = MIM_STYLE;
11198     mi.dwStyle = 0;
11199     SetLastError(0xdeadbeef);
11200     ret = pGetMenuInfo(hmenu, &mi);
11201     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11202
11203     return mi.dwStyle;
11204 }
11205
11206 static void test_menu_messages(void)
11207 {
11208     MSG msg;
11209     WNDCLASSA cls;
11210     HMENU hmenu, hmenu_popup;
11211     HWND hwnd;
11212     DWORD style;
11213
11214     if (!pGetMenuInfo || !pSetMenuInfo)
11215     {
11216         skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11217         return;
11218     }
11219     cls.style = 0;
11220     cls.lpfnWndProc = parent_menu_proc;
11221     cls.cbClsExtra = 0;
11222     cls.cbWndExtra = 0;
11223     cls.hInstance = GetModuleHandleA(0);
11224     cls.hIcon = 0;
11225     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11226     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11227     cls.lpszMenuName = NULL;
11228     cls.lpszClassName = "TestMenuClass";
11229     UnregisterClass(cls.lpszClassName, cls.hInstance);
11230     if (!RegisterClassA(&cls)) assert(0);
11231
11232     SetLastError(0xdeadbeef);
11233     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11234                            100, 100, 200, 200, 0, 0, 0, NULL);
11235     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11236
11237     SetLastError(0xdeadbeef);
11238     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11239     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11240
11241     SetMenu(hwnd, hmenu);
11242     SetForegroundWindow( hwnd );
11243
11244     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11245     style = get_menu_style(hmenu);
11246     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11247
11248     hmenu_popup = GetSubMenu(hmenu, 0);
11249     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11250     style = get_menu_style(hmenu_popup);
11251     ok(style == 0, "expected 0, got %u\n", style);
11252
11253     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11254     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11255     style = get_menu_style(hmenu_popup);
11256     ok(style == 0, "expected 0, got %u\n", style);
11257
11258     /* Alt+E, Enter */
11259     trace("testing a popup menu command\n");
11260     flush_sequence();
11261     keybd_event(VK_MENU, 0, 0, 0);
11262     keybd_event('E', 0, 0, 0);
11263     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11264     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11265     keybd_event(VK_RETURN, 0, 0, 0);
11266     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11267     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11268     {
11269         TranslateMessage(&msg);
11270         DispatchMessage(&msg);
11271     }
11272     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11273
11274     /* Alt+F, Right, Enter */
11275     trace("testing submenu of a popup menu command\n");
11276     flush_sequence();
11277     keybd_event(VK_MENU, 0, 0, 0);
11278     keybd_event('F', 0, 0, 0);
11279     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11280     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11281     keybd_event(VK_RIGHT, 0, 0, 0);
11282     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11283     keybd_event(VK_RETURN, 0, 0, 0);
11284     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11285     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11286     {
11287         TranslateMessage(&msg);
11288         DispatchMessage(&msg);
11289     }
11290     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11291
11292     set_menu_style(hmenu, 0);
11293     style = get_menu_style(hmenu);
11294     ok(style == 0, "expected 0, got %u\n", style);
11295
11296     hmenu_popup = GetSubMenu(hmenu, 0);
11297     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11298     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11299     style = get_menu_style(hmenu_popup);
11300     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11301
11302     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11303     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11304     style = get_menu_style(hmenu_popup);
11305     ok(style == 0, "expected 0, got %u\n", style);
11306
11307     /* Alt+F, Right, Enter */
11308     trace("testing submenu of a popup menu command\n");
11309     flush_sequence();
11310     keybd_event(VK_MENU, 0, 0, 0);
11311     keybd_event('F', 0, 0, 0);
11312     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11313     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11314     keybd_event(VK_RIGHT, 0, 0, 0);
11315     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11316     keybd_event(VK_RETURN, 0, 0, 0);
11317     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11318     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11319     {
11320         TranslateMessage(&msg);
11321         DispatchMessage(&msg);
11322     }
11323     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11324
11325     DestroyWindow(hwnd);
11326     DestroyMenu(hmenu);
11327 }
11328
11329
11330 static void test_paintingloop(void)
11331 {
11332     HWND hwnd;
11333
11334     paint_loop_done = 0;
11335     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11336                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11337                                 100, 100, 100, 100, 0, 0, 0, NULL );
11338     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11339     ShowWindow(hwnd,SW_NORMAL);
11340     SetFocus(hwnd);
11341
11342     while (!paint_loop_done)
11343     {
11344         MSG msg;
11345         if (PeekMessageA(&msg, 0, 0, 0, 1))
11346         {
11347             TranslateMessage(&msg);
11348             DispatchMessage(&msg);
11349         }
11350     }
11351     DestroyWindow(hwnd);
11352 }
11353
11354 static void test_defwinproc(void)
11355 {
11356     HWND hwnd;
11357     MSG msg;
11358     int gotwmquit = FALSE;
11359     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
11360     assert(hwnd);
11361     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
11362     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
11363         if( msg.message == WM_QUIT) gotwmquit = TRUE;
11364         DispatchMessageA( &msg );
11365     }
11366     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
11367     DestroyWindow( hwnd);
11368 }
11369
11370 START_TEST(msg)
11371 {
11372     BOOL ret;
11373     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11374
11375     init_procs();
11376
11377     if (!RegisterWindowClasses()) assert(0);
11378
11379     if (pSetWinEventHook)
11380     {
11381         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11382                                        GetModuleHandleA(0), win_event_proc,
11383                                        0, GetCurrentThreadId(),
11384                                        WINEVENT_INCONTEXT);
11385         if (pIsWinEventHookInstalled && hEvent_hook)
11386         {
11387             UINT event;
11388             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11389                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11390         }
11391     }
11392     if (!hEvent_hook) skip( "no win event hook support\n" );
11393
11394     cbt_hook_thread_id = GetCurrentThreadId();
11395     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11396     if (!hCBT_hook) skip( "cannot set global hook, will skip hook tests\n" );
11397
11398     test_winevents();
11399
11400     /* Fix message sequences before removing 4 lines below */
11401 #if 1
11402     if (pUnhookWinEvent && hEvent_hook)
11403     {
11404         ret = pUnhookWinEvent(hEvent_hook);
11405         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11406         pUnhookWinEvent = 0;
11407     }
11408     hEvent_hook = 0;
11409 #endif
11410
11411     test_ShowWindow();
11412     test_PeekMessage();
11413     test_PeekMessage2();
11414     test_scrollwindowex();
11415     test_messages();
11416     test_setwindowpos();
11417     test_showwindow();
11418     invisible_parent_tests();
11419     test_mdi_messages();
11420     test_button_messages();
11421     test_static_messages();
11422     test_listbox_messages();
11423     test_combobox_messages();
11424     test_wmime_keydown_message();
11425     test_paint_messages();
11426     test_interthread_messages();
11427     test_message_conversion();
11428     test_accelerators();
11429     test_timers();
11430     test_timers_no_wnd();
11431     if (hCBT_hook) test_set_hook();
11432     test_DestroyWindow();
11433     test_DispatchMessage();
11434     test_SendMessageTimeout();
11435     test_edit_messages();
11436     test_quit_message();
11437     test_SetActiveWindow();
11438
11439     if (!pTrackMouseEvent)
11440         skip("TrackMouseEvent is not available\n");
11441     else
11442         test_TrackMouseEvent();
11443
11444     test_SetWindowRgn();
11445     test_sys_menu();
11446     test_dialog_messages();
11447     test_nullCallback();
11448     test_dbcs_wm_char();
11449     test_menu_messages();
11450     test_paintingloop();
11451     test_defwinproc();
11452     /* keep it the last test, under Windows it tends to break the tests
11453      * which rely on active/foreground windows being correct.
11454      */
11455     test_SetForegroundWindow();
11456
11457     UnhookWindowsHookEx(hCBT_hook);
11458     if (pUnhookWinEvent && hEvent_hook)
11459     {
11460         ret = pUnhookWinEvent(hEvent_hook);
11461         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11462         SetLastError(0xdeadbeef);
11463         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11464         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11465            GetLastError() == 0xdeadbeef, /* Win9x */
11466            "unexpected error %d\n", GetLastError());
11467     }
11468 }