user32/tests: Remove tests for internal DDE handle format, we don't care how the...
[wine] / dlls / user32 / tests / msg.c
1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004, 2005 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE        0x0800
41 #define SWP_NOCLIENTMOVE        0x1000
42 #define SWP_STATECHANGED        0x8000
43
44 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
45
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER         0x0118
52 #endif
53
54 #define WND_PARENT_ID           1
55 #define WND_POPUP_ID            2
56 #define WND_CHILD_ID            3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61
62 /* encoded DRAWITEMSTRUCT into an LPARAM */
63 typedef struct
64 {
65     union
66     {
67         struct
68         {
69             UINT type    : 4;  /* ODT_* flags */
70             UINT ctl_id  : 4;  /* Control ID */
71             UINT item_id : 4;  /* Menu item ID */
72             UINT action  : 4;  /* ODA_* flags */
73             UINT state   : 16; /* ODS_* flags */
74         } item;
75         LPARAM lp;
76     } u;
77 } DRAW_ITEM_STRUCT;
78
79 static BOOL test_DestroyWindow_flag;
80 static HWINEVENTHOOK hEvent_hook;
81 static HHOOK hCBT_hook;
82 static DWORD cbt_hook_thread_id;
83
84 static const WCHAR testWindowClassW[] =
85 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
86
87 /*
88 FIXME: add tests for these
89 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
90  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
91  WS_THICKFRAME: thick border
92  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
93  WS_BORDER (default for overlapped windows): single black border
94  none (default for child (and popup?) windows): no border
95 */
96
97 typedef enum {
98     sent=0x1,
99     posted=0x2,
100     parent=0x4,
101     wparam=0x8,
102     lparam=0x10,
103     defwinproc=0x20,
104     beginpaint=0x40,
105     optional=0x80,
106     hook=0x100,
107     winevent_hook=0x200
108 } msg_flags_t;
109
110 struct message {
111     UINT message;          /* the WM_* code */
112     msg_flags_t flags;     /* message props */
113     WPARAM wParam;         /* expected value of wParam */
114     LPARAM lParam;         /* expected value of lParam */
115     WPARAM wp_mask;        /* mask for wParam checks */
116     LPARAM lp_mask;        /* mask for lParam checks */
117 };
118
119 struct recvd_message {
120     UINT message;          /* the WM_* code */
121     msg_flags_t flags;     /* message props */
122     HWND hwnd;             /* window that received the message */
123     WPARAM wParam;         /* expected value of wParam */
124     LPARAM lParam;         /* expected value of lParam */
125     int line;              /* source line where logged */
126     const char *descr;     /* description for trace output */
127     char output[512];      /* trace output */
128 };
129
130 /* Empty message sequence */
131 static const struct message WmEmptySeq[] =
132 {
133     { 0 }
134 };
135 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
136 static const struct message WmCreateOverlappedSeq[] = {
137     { HCBT_CREATEWND, hook },
138     { WM_GETMINMAXINFO, sent },
139     { WM_NCCREATE, sent },
140     { WM_NCCALCSIZE, sent|wparam, 0 },
141     { 0x0093, sent|defwinproc|optional },
142     { 0x0094, sent|defwinproc|optional },
143     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
144     { WM_CREATE, sent },
145     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
146     { 0 }
147 };
148 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
149  * for a not visible overlapped window.
150  */
151 static const struct message WmSWP_ShowOverlappedSeq[] = {
152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
153     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
154     { WM_NCPAINT, sent|wparam|optional, 1 },
155     { WM_GETTEXT, sent|defwinproc|optional },
156     { WM_ERASEBKGND, sent|optional },
157     { HCBT_ACTIVATE, hook },
158     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
159     { WM_NOTIFYFORMAT, sent|optional },
160     { WM_QUERYUISTATE, sent|optional },
161     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
162     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
163     { WM_ACTIVATEAPP, sent|wparam, 1 },
164     { WM_NCACTIVATE, sent|wparam, 1 },
165     { WM_GETTEXT, sent|defwinproc|optional },
166     { WM_ACTIVATE, sent|wparam, 1 },
167     { HCBT_SETFOCUS, hook },
168     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
169     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
170     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
171     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
172     { WM_GETTEXT, sent|optional },
173     { WM_NCPAINT, sent|wparam|optional, 1 },
174     { WM_GETTEXT, sent|defwinproc|optional },
175     { WM_ERASEBKGND, sent|optional },
176     /* Win9x adds SWP_NOZORDER below */
177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
178     { WM_GETTEXT, sent|optional },
179     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
180     { WM_NCPAINT, sent|wparam|optional, 1 },
181     { WM_ERASEBKGND, sent|optional },
182     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
183     { WM_SYNCPAINT, sent|optional },
184     { WM_GETTITLEBARINFOEX, sent|optional },
185     { WM_PAINT, sent|optional },
186     { WM_NCPAINT, sent|beginpaint|optional },
187     { WM_GETTEXT, sent|defwinproc|optional },
188     { WM_ERASEBKGND, sent|beginpaint|optional },
189     { 0 }
190 };
191 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
192  * for a visible overlapped window.
193  */
194 static const struct message WmSWP_HideOverlappedSeq[] = {
195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
196     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
197     { HCBT_ACTIVATE, hook|optional },
198     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
199     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
200     { WM_NCACTIVATE, sent|optional },
201     { WM_ACTIVATE, sent|optional },
202     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
203     { 0 }
204 };
205
206 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
207  * for a visible overlapped window.
208  */
209 static const struct message WmSWP_ResizeSeq[] = {
210     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
211     { WM_GETMINMAXINFO, sent|defwinproc },
212     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
213     { WM_NCPAINT, sent|optional },
214     { WM_GETTEXT, sent|defwinproc|optional },
215     { WM_ERASEBKGND, sent|optional },
216     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
217     { WM_SIZE, sent|defwinproc|optional },
218     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
219     { WM_NCPAINT, sent|optional },
220     { WM_GETTEXT, sent|defwinproc|optional },
221     { WM_ERASEBKGND, sent|optional },
222     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
224     { 0 }
225 };
226
227 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
228  * for a visible popup window.
229  */
230 static const struct message WmSWP_ResizePopupSeq[] = {
231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
232     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
233     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
234     { WM_NCPAINT, sent|optional },
235     { WM_GETTEXT, sent|defwinproc|optional },
236     { WM_ERASEBKGND, sent|optional },
237     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
238     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
239     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
240     { WM_NCPAINT, sent|optional },
241     { WM_GETTEXT, sent|defwinproc|optional },
242     { WM_ERASEBKGND, sent|optional },
243     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
244     { 0 }
245 };
246
247 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
248  * for a visible overlapped window.
249  */
250 static const struct message WmSWP_MoveSeq[] = {
251     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
252     { WM_NCPAINT, sent|optional },
253     { WM_GETTEXT, sent|defwinproc|optional },
254     { WM_ERASEBKGND, sent|optional },
255     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
256     { WM_MOVE, sent|defwinproc|wparam, 0 },
257     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
258     { 0 }
259 };
260 /* Resize with SetWindowPos(SWP_NOZORDER)
261  * for a visible overlapped window
262  * SWP_NOZORDER is stripped by the logging code
263  */
264 static const struct message WmSWP_ResizeNoZOrder[] = {
265     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
266     { WM_GETMINMAXINFO, sent|defwinproc },
267     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
268     { WM_NCPAINT, sent|optional },
269     { WM_GETTEXT, sent|defwinproc|optional },
270     { WM_ERASEBKGND, sent|optional },
271     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
272       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
273     { WM_MOVE, sent|defwinproc|optional },
274     { WM_SIZE, sent|defwinproc|optional },
275     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
276     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
277     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
278     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
279     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
280     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
281     { 0 }
282 };
283
284 /* Switch visible mdi children */
285 static const struct message WmSwitchChild[] = {
286     /* Switch MDI child */
287     { WM_MDIACTIVATE, sent },/* in the MDI client */
288     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
289     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
290     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
291     /* Deactivate 2nd MDI child */
292     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
293     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
294     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
295     /* Preparing for maximize and maximaze the 1st MDI child */
296     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
297     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
298     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
299     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
300     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
301     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
302     /* Lock redraw 2nd MDI child */
303     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
304     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
305     /* Restore 2nd MDI child */
306     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
307     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
308     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
309     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
310     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
311     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
312     /* Redraw 2nd MDI child */
313     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
314     /* Redraw MDI frame */
315     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
316     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
317     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
318     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
320     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
321     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
322     { HCBT_SETFOCUS, hook },
323     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
324     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
325     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
326     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
327     { WM_SETFOCUS, sent },/* in the MDI client */
328     { HCBT_SETFOCUS, hook },
329     { WM_KILLFOCUS, sent },/* in the MDI client */
330     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
331     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
332     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
333     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
334     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
335     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
336     { 0 }
337 };
338
339 /* Switch visible not maximized mdi children */
340 static const struct message WmSwitchNotMaximizedChild[] = {
341     /* Switch not maximized MDI child */
342     { WM_MDIACTIVATE, sent },/* in the MDI client */
343     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
344     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
345     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
346     /* Deactivate 1st MDI child */
347     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
348     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
349     /* Activate 2nd MDI child */
350     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
351     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
352     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
353     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
354     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
355     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
356     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
357     { HCBT_SETFOCUS, hook },
358     { WM_KILLFOCUS, sent }, /* in the  MDI client */
359     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
360     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
361     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
362     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
363     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
364     { 0 }
365 };
366
367
368 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
369                 SWP_NOZORDER|SWP_FRAMECHANGED)
370  * for a visible overlapped window with WS_CLIPCHILDREN style set.
371  */
372 static const struct message WmSWP_FrameChanged_clip[] = {
373     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
374     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
375     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
376     { WM_GETTEXT, sent|parent|defwinproc|optional },
377     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
378     { WM_NCPAINT, sent }, /* wparam != 1 */
379     { WM_ERASEBKGND, sent },
380     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
381     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
382     { WM_PAINT, sent },
383     { 0 }
384 };
385 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
386                 SWP_NOZORDER|SWP_FRAMECHANGED)
387  * for a visible overlapped window.
388  */
389 static const struct message WmSWP_FrameChangedDeferErase[] = {
390     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
391     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
392     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
393     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
394     { WM_PAINT, sent|parent|optional },
395     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
396     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
397     { WM_PAINT, sent },
398     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
399     { WM_ERASEBKGND, sent|beginpaint|optional },
400     { 0 }
401 };
402
403 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
404                 SWP_NOZORDER|SWP_FRAMECHANGED)
405  * for a visible overlapped window without WS_CLIPCHILDREN style set.
406  */
407 static const struct message WmSWP_FrameChanged_noclip[] = {
408     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
409     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
410     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
411     { WM_GETTEXT, sent|parent|defwinproc|optional },
412     { WM_ERASEBKGND, sent|parent|optional },
413     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
414     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
415     { WM_PAINT, sent },
416     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
417     { WM_ERASEBKGND, sent|beginpaint|optional },
418     { 0 }
419 };
420
421 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
422 static const struct message WmShowOverlappedSeq[] = {
423     { WM_SHOWWINDOW, sent|wparam, 1 },
424     { WM_NCPAINT, sent|wparam|optional, 1 },
425     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
426     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
427     { WM_NCPAINT, sent|wparam|optional, 1 },
428     { WM_GETTEXT, sent|defwinproc|optional },
429     { WM_ERASEBKGND, sent|optional },
430     { HCBT_ACTIVATE, hook },
431     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
432     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
433     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
434     { WM_NCPAINT, sent|wparam|optional, 1 },
435     { WM_ACTIVATEAPP, sent|wparam, 1 },
436     { WM_NCACTIVATE, sent|wparam, 1 },
437     { WM_GETTEXT, sent|defwinproc|optional },
438     { WM_ACTIVATE, sent|wparam, 1 },
439     { HCBT_SETFOCUS, hook },
440     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
441     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
442     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
443     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
444     { WM_GETTEXT, sent|optional },
445     { WM_NCPAINT, sent|wparam|optional, 1 },
446     { WM_GETTEXT, sent|defwinproc|optional },
447     { WM_ERASEBKGND, sent|optional },
448     /* Win9x adds SWP_NOZORDER below */
449     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
450     { WM_NCCALCSIZE, sent|optional },
451     { WM_GETTEXT, sent|optional },
452     { WM_NCPAINT, sent|optional },
453     { WM_ERASEBKGND, sent|optional },
454     { WM_SYNCPAINT, sent|optional },
455 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
456        * messages. Does that mean that CreateWindow doesn't set initial
457        * window dimensions for overlapped windows?
458        */
459     { WM_SIZE, sent },
460     { WM_MOVE, sent },
461 #endif
462     { WM_PAINT, sent|optional },
463     { WM_NCPAINT, sent|beginpaint|optional },
464     { 0 }
465 };
466 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
467 static const struct message WmShowMaxOverlappedSeq[] = {
468     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
469     { WM_GETMINMAXINFO, sent },
470     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
471     { WM_GETMINMAXINFO, sent|defwinproc },
472     { WM_NCCALCSIZE, sent|wparam, TRUE },
473     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
474     { HCBT_ACTIVATE, hook },
475     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
476     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
477     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
478     { WM_ACTIVATEAPP, sent|wparam, 1 },
479     { WM_NCACTIVATE, sent|wparam, 1 },
480     { WM_GETTEXT, sent|defwinproc|optional },
481     { WM_ACTIVATE, sent|wparam, 1 },
482     { HCBT_SETFOCUS, hook },
483     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
484     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
485     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
486     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
487     { WM_GETTEXT, sent|optional },
488     { WM_NCPAINT, sent|wparam|optional, 1 },
489     { WM_GETTEXT, sent|defwinproc|optional },
490     { WM_ERASEBKGND, sent|optional },
491     /* Win9x adds SWP_NOZORDER below */
492     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
493     { WM_MOVE, sent|defwinproc },
494     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
495     { WM_GETTEXT, sent|optional },
496     { WM_NCCALCSIZE, sent|optional },
497     { WM_NCPAINT, sent|optional },
498     { WM_ERASEBKGND, sent|optional },
499     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
500     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
501     { WM_SYNCPAINT, sent|optional },
502     { WM_GETTITLEBARINFOEX, sent|optional },
503     { WM_PAINT, sent|optional },
504     { WM_NCPAINT, sent|beginpaint|optional },
505     { WM_ERASEBKGND, sent|beginpaint|optional },
506     { 0 }
507 };
508 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
509 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
510     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
511     { WM_GETTEXT, sent|optional },
512     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
513     { WM_GETMINMAXINFO, sent|defwinproc },
514     { WM_NCCALCSIZE, sent|wparam, TRUE },
515     { WM_NCPAINT, sent|optional },
516     { WM_GETTEXT, sent|defwinproc|optional },
517     { WM_ERASEBKGND, sent|optional },
518     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
519     { WM_MOVE, sent|defwinproc|optional },
520     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
521     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
522     { WM_NCPAINT, sent|optional },
523     { WM_ERASEBKGND, sent|optional },
524     { WM_PAINT, sent|optional },
525     { WM_GETTITLEBARINFOEX, sent|optional },
526     { WM_NCPAINT, sent|beginpaint|optional },
527     { WM_ERASEBKGND, sent|beginpaint|optional },
528     { 0 }
529 };
530 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
531 static const struct message WmShowRestoreMinOverlappedSeq[] = {
532     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
533     { WM_QUERYOPEN, sent|optional },
534     { WM_GETTEXT, sent|optional },
535     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
536     { WM_GETMINMAXINFO, sent|defwinproc },
537     { WM_NCCALCSIZE, sent|wparam, TRUE },
538     { HCBT_ACTIVATE, hook },
539     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
540     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
541     { WM_ACTIVATEAPP, sent|wparam, 1 },
542     { WM_NCACTIVATE, sent|wparam, 1 },
543     { WM_GETTEXT, sent|defwinproc|optional },
544     { WM_ACTIVATE, sent|wparam, 1 },
545     { HCBT_SETFOCUS, hook },
546     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
547     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
548     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
549     { WM_GETTEXT, sent|optional },
550     { WM_NCPAINT, sent|wparam|optional, 1 },
551     { WM_GETTEXT, sent|defwinproc|optional },
552     { WM_ERASEBKGND, sent },
553     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
554     { WM_MOVE, sent|defwinproc },
555     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
556     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
557     { WM_NCPAINT, sent|wparam|optional, 1 },
558     { WM_ERASEBKGND, sent|optional },
559     { WM_ACTIVATE, sent|wparam, 1 },
560     { WM_GETTEXT, sent|optional },
561     { WM_PAINT, sent|optional },
562     { WM_GETTITLEBARINFOEX, sent|optional },
563     { WM_NCPAINT, sent|beginpaint|optional },
564     { WM_ERASEBKGND, sent|beginpaint|optional },
565     { 0 }
566 };
567 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
568 static const struct message WmShowMinOverlappedSeq[] = {
569     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
570     { HCBT_SETFOCUS, hook },
571     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
572     { WM_KILLFOCUS, sent },
573     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
574     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
575     { WM_GETTEXT, sent|optional },
576     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
577     { WM_GETMINMAXINFO, sent|defwinproc },
578     { WM_NCCALCSIZE, sent|wparam, TRUE },
579     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
580     { WM_NCPAINT, sent|optional },
581     { WM_GETTEXT, sent|defwinproc|optional },
582     { WM_WINDOWPOSCHANGED, sent },
583     { WM_MOVE, sent|defwinproc },
584     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
585     { WM_NCCALCSIZE, sent|optional },
586     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
587     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
588     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
589     { WM_NCACTIVATE, sent|wparam, 0 },
590     { WM_GETTEXT, sent|defwinproc|optional },
591     { WM_ACTIVATE, sent },
592     { WM_ACTIVATEAPP, sent|wparam, 0 },
593
594     /* Vista sometimes restores the window right away... */
595     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
596     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
597     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
598     { WM_QUERYOPEN, sent|optional },
599     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
600     { WM_GETMINMAXINFO, sent|optional|defwinproc },
601     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
602     { HCBT_ACTIVATE, hook|optional },
603     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
604     { WM_NCACTIVATE, sent|optional },
605     { WM_GETTEXT, sent|optional },
606     { WM_ACTIVATE, sent|optional|wparam, 1 },
607     { HCBT_SETFOCUS, hook|optional },
608     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
609     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
610     { WM_SETFOCUS, sent|optional },
611     { WM_NCPAINT, sent|optional },
612     { WM_GETTEXT, sent|defwinproc|optional },
613     { WM_ERASEBKGND, sent|optional },
614     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
615     { WM_MOVE, sent|defwinproc|optional },
616     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
617     { WM_ACTIVATE, sent|optional|wparam, 1 },
618     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
619     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
620
621     { WM_PAINT, sent|optional },
622     { WM_NCPAINT, sent|beginpaint|optional },
623     { WM_ERASEBKGND, sent|beginpaint|optional },
624     { 0 }
625 };
626 /* ShowWindow(SW_HIDE) for a visible overlapped window */
627 static const struct message WmHideOverlappedSeq[] = {
628     { WM_SHOWWINDOW, sent|wparam, 0 },
629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
630     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
631     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
632     { WM_SIZE, sent|optional }, /* XP doesn't send it */
633     { WM_MOVE, sent|optional }, /* XP doesn't send it */
634     { WM_NCACTIVATE, sent|wparam, 0 },
635     { WM_ACTIVATE, sent|wparam, 0 },
636     { WM_ACTIVATEAPP, sent|wparam, 0 },
637     { WM_KILLFOCUS, sent|wparam, 0 },
638     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
639     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
640     { 0 }
641 };
642 /* DestroyWindow for a visible overlapped window */
643 static const struct message WmDestroyOverlappedSeq[] = {
644     { HCBT_DESTROYWND, hook },
645     { 0x0090, sent|optional },
646     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
647     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
648     { 0x0090, sent|optional },
649     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
650     { WM_NCACTIVATE, sent|optional|wparam, 0 },
651     { WM_ACTIVATE, sent|optional },
652     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
653     { WM_KILLFOCUS, sent|optional|wparam, 0 },
654     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
655     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
656     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
657     { WM_DESTROY, sent },
658     { WM_NCDESTROY, sent },
659     { 0 }
660 };
661 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
662 static const struct message WmCreateMaxPopupSeq[] = {
663     { HCBT_CREATEWND, hook },
664     { WM_NCCREATE, sent },
665     { WM_NCCALCSIZE, sent|wparam, 0 },
666     { WM_CREATE, sent },
667     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
668     { WM_SIZE, sent|wparam, SIZE_RESTORED },
669     { WM_MOVE, sent },
670     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
671     { WM_GETMINMAXINFO, sent },
672     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
673     { WM_NCCALCSIZE, sent|wparam, TRUE },
674     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
675     { WM_MOVE, sent|defwinproc },
676     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
677     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
678     { WM_SHOWWINDOW, sent|wparam, 1 },
679     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
680     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
681     { HCBT_ACTIVATE, hook },
682     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
683     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
684     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
685     { WM_NCPAINT, sent|wparam|optional, 1 },
686     { WM_ERASEBKGND, sent|optional },
687     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
688     { WM_ACTIVATEAPP, sent|wparam, 1 },
689     { WM_NCACTIVATE, sent },
690     { WM_ACTIVATE, sent|wparam, 1 },
691     { HCBT_SETFOCUS, hook },
692     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
693     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
694     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
695     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
696     { WM_GETTEXT, sent|optional },
697     { WM_SYNCPAINT, sent|wparam|optional, 4 },
698     { WM_NCPAINT, sent|wparam|optional, 1 },
699     { WM_ERASEBKGND, sent|optional },
700     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
701     { WM_ERASEBKGND, sent|defwinproc|optional },
702     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
703     { 0 }
704 };
705 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
706 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
707     { HCBT_CREATEWND, hook },
708     { WM_NCCREATE, sent },
709     { WM_NCCALCSIZE, sent|wparam, 0 },
710     { WM_CREATE, sent },
711     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
712     { WM_SIZE, sent|wparam, SIZE_RESTORED },
713     { WM_MOVE, sent },
714     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
715     { WM_GETMINMAXINFO, sent },
716     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
717     { WM_NCCALCSIZE, sent|wparam, TRUE },
718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
719     { WM_MOVE, sent|defwinproc },
720     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
722     { 0 }
723 };
724 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
725 static const struct message WmShowMaxPopupResizedSeq[] = {
726     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
727     { WM_GETMINMAXINFO, sent },
728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
729     { WM_NCCALCSIZE, sent|wparam, TRUE },
730     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
731     { HCBT_ACTIVATE, hook },
732     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
733     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
734     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
735     { WM_NCPAINT, sent|wparam|optional, 1 },
736     { WM_ERASEBKGND, sent|optional },
737     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
738     { WM_ACTIVATEAPP, sent|wparam, 1 },
739     { WM_NCACTIVATE, sent },
740     { WM_ACTIVATE, sent|wparam, 1 },
741     { HCBT_SETFOCUS, hook },
742     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
743     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
744     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
745     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
746     { WM_GETTEXT, sent|optional },
747     { WM_NCPAINT, sent|wparam|optional, 1 },
748     { WM_ERASEBKGND, sent|optional },
749     { WM_WINDOWPOSCHANGED, sent },
750     /* WinNT4.0 sends WM_MOVE */
751     { WM_MOVE, sent|defwinproc|optional },
752     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
753     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
754     { 0 }
755 };
756 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
757 static const struct message WmShowMaxPopupSeq[] = {
758     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
759     { WM_GETMINMAXINFO, sent },
760     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
761     { WM_NCCALCSIZE, sent|wparam, TRUE },
762     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
763     { HCBT_ACTIVATE, hook },
764     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
765     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
766     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
767     { WM_ACTIVATEAPP, sent|wparam, 1 },
768     { WM_NCACTIVATE, sent },
769     { WM_ACTIVATE, sent|wparam, 1 },
770     { HCBT_SETFOCUS, hook },
771     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
772     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
773     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
774     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
775     { WM_GETTEXT, sent|optional },
776     { WM_SYNCPAINT, sent|wparam|optional, 4 },
777     { WM_NCPAINT, sent|wparam|optional, 1 },
778     { WM_ERASEBKGND, sent|optional },
779     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
780     { WM_ERASEBKGND, sent|defwinproc|optional },
781     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
782     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
783     { 0 }
784 };
785 /* CreateWindow(WS_VISIBLE) for popup window */
786 static const struct message WmCreatePopupSeq[] = {
787     { HCBT_CREATEWND, hook },
788     { WM_NCCREATE, sent },
789     { WM_NCCALCSIZE, sent|wparam, 0 },
790     { WM_CREATE, sent },
791     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
792     { WM_SIZE, sent|wparam, SIZE_RESTORED },
793     { WM_MOVE, sent },
794     { WM_SHOWWINDOW, sent|wparam, 1 },
795     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
796     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
797     { HCBT_ACTIVATE, hook },
798     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
799     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
800     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
801     { WM_NCPAINT, sent|wparam|optional, 1 },
802     { WM_ERASEBKGND, sent|optional },
803     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
804     { WM_ACTIVATEAPP, sent|wparam, 1 },
805     { WM_NCACTIVATE, sent },
806     { WM_ACTIVATE, sent|wparam, 1 },
807     { HCBT_SETFOCUS, hook },
808     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
809     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
810     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
811     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
812     { WM_GETTEXT, sent|optional },
813     { WM_SYNCPAINT, sent|wparam|optional, 4 },
814     { WM_NCPAINT, sent|wparam|optional, 1 },
815     { WM_ERASEBKGND, sent|optional },
816     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
817     { 0 }
818 };
819 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
820 static const struct message WmShowVisMaxPopupSeq[] = {
821     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
822     { WM_GETMINMAXINFO, sent },
823     { WM_GETTEXT, sent|optional },
824     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
825     { WM_GETTEXT, sent|optional },
826     { WM_NCCALCSIZE, sent|wparam, TRUE },
827     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
828     { WM_NCPAINT, sent|wparam|optional, 1 },
829     { WM_ERASEBKGND, sent|optional },
830     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
831     { WM_MOVE, sent|defwinproc },
832     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
833     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
834     { 0 }
835 };
836 /* CreateWindow (for a child popup window, not initially visible) */
837 static const struct message WmCreateChildPopupSeq[] = {
838     { HCBT_CREATEWND, hook },
839     { WM_NCCREATE, sent }, 
840     { WM_NCCALCSIZE, sent|wparam, 0 },
841     { WM_CREATE, sent },
842     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
843     { WM_SIZE, sent|wparam, SIZE_RESTORED },
844     { WM_MOVE, sent },
845     { 0 }
846 };
847 /* CreateWindow (for a popup window, not initially visible,
848  * which sets WS_VISIBLE in WM_CREATE handler)
849  */
850 static const struct message WmCreateInvisiblePopupSeq[] = {
851     { HCBT_CREATEWND, hook },
852     { WM_NCCREATE, sent }, 
853     { WM_NCCALCSIZE, sent|wparam, 0 },
854     { WM_CREATE, sent },
855     { WM_STYLECHANGING, sent },
856     { WM_STYLECHANGED, sent },
857     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
858     { WM_SIZE, sent|wparam, SIZE_RESTORED },
859     { WM_MOVE, sent },
860     { 0 }
861 };
862 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
863  * for a popup window with WS_VISIBLE style set
864  */
865 static const struct message WmShowVisiblePopupSeq_2[] = {
866     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
867     { 0 }
868 };
869 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
870  * for a popup window with WS_VISIBLE style set
871  */
872 static const struct message WmShowVisiblePopupSeq_3[] = {
873     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
874     { HCBT_ACTIVATE, hook },
875     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
876     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
877     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
878     { WM_NCACTIVATE, sent },
879     { WM_ACTIVATE, sent|wparam, 1 },
880     { HCBT_SETFOCUS, hook },
881     { WM_KILLFOCUS, sent|parent },
882     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
883     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
884     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
885     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
886     { WM_SETFOCUS, sent|defwinproc },
887     { WM_GETTEXT, sent|optional },
888     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
889     { 0 }
890 };
891 /* CreateWindow (for child window, not initially visible) */
892 static const struct message WmCreateChildSeq[] = {
893     { HCBT_CREATEWND, hook },
894     { WM_NCCREATE, sent }, 
895     /* child is inserted into parent's child list after WM_NCCREATE returns */
896     { WM_NCCALCSIZE, sent|wparam, 0 },
897     { WM_CREATE, sent },
898     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
899     { WM_SIZE, sent|wparam, SIZE_RESTORED },
900     { WM_MOVE, sent },
901     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
902     { 0 }
903 };
904 /* CreateWindow (for maximized child window, not initially visible) */
905 static const struct message WmCreateMaximizedChildSeq[] = {
906     { HCBT_CREATEWND, hook },
907     { WM_NCCREATE, sent }, 
908     { WM_NCCALCSIZE, sent|wparam, 0 },
909     { WM_CREATE, sent },
910     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
911     { WM_SIZE, sent|wparam, SIZE_RESTORED },
912     { WM_MOVE, sent },
913     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
914     { WM_GETMINMAXINFO, sent },
915     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
916     { WM_NCCALCSIZE, sent|wparam, 1 },
917     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
918     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
919     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
920     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
921     { 0 }
922 };
923 /* CreateWindow (for a child window, initially visible) */
924 static const struct message WmCreateVisibleChildSeq[] = {
925     { HCBT_CREATEWND, hook },
926     { WM_NCCREATE, sent }, 
927     /* child is inserted into parent's child list after WM_NCCREATE returns */
928     { WM_NCCALCSIZE, sent|wparam, 0 },
929     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
930     { WM_CREATE, sent },
931     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
932     { WM_SIZE, sent|wparam, SIZE_RESTORED },
933     { WM_MOVE, sent },
934     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
935     { WM_SHOWWINDOW, sent|wparam, 1 },
936     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
937     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
938     { WM_ERASEBKGND, sent|parent|optional },
939     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
940     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
942     { 0 }
943 };
944 /* ShowWindow(SW_SHOW) for a not visible child window */
945 static const struct message WmShowChildSeq[] = {
946     { WM_SHOWWINDOW, sent|wparam, 1 },
947     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
948     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
949     { WM_ERASEBKGND, sent|parent|optional },
950     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
951     { 0 }
952 };
953 /* ShowWindow(SW_HIDE) for a visible child window */
954 static const struct message WmHideChildSeq[] = {
955     { WM_SHOWWINDOW, sent|wparam, 0 },
956     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
957     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
958     { WM_ERASEBKGND, sent|parent|optional },
959     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
960     { 0 }
961 };
962 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
963 static const struct message WmHideChildSeq2[] = {
964     { WM_SHOWWINDOW, sent|wparam, 0 },
965     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
966     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
967     { WM_ERASEBKGND, sent|parent|optional },
968     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
969     { 0 }
970 };
971 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
972  * for a not visible child window
973  */
974 static const struct message WmShowChildSeq_2[] = {
975     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
976     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
977     { WM_CHILDACTIVATE, sent },
978     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
979     { 0 }
980 };
981 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
982  * for a not visible child window
983  */
984 static const struct message WmShowChildSeq_3[] = {
985     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
986     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
987     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
988     { 0 }
989 };
990 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
991  * for a visible child window with a caption
992  */
993 static const struct message WmShowChildSeq_4[] = {
994     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
995     { WM_CHILDACTIVATE, sent },
996     { 0 }
997 };
998 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
999 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1000     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1001     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1002     { WM_NCCALCSIZE, sent|wparam, 1 },
1003     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1004     { WM_CHILDACTIVATE, sent|optional },
1005     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1006     { WM_MOVE, sent|defwinproc },
1007     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1008     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1009     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1010     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1011     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1012     { WM_GETTEXT, sent|optional },
1013     { 0 }
1014 };
1015 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1016 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1017     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1018     { 0 }
1019 };
1020 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1021 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1022     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1023     { WM_GETMINMAXINFO, sent },
1024     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1025     { WM_NCCALCSIZE, sent|wparam, 1 },
1026     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1027     { WM_CHILDACTIVATE, sent },
1028     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1029     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1030     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1031     { 0 }
1032 };
1033 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1034 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1035     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1036     { 0 }
1037 };
1038 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1039 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1040     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1041     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1042     { WM_NCCALCSIZE, sent|wparam, 1 },
1043     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1044     { WM_CHILDACTIVATE, sent },
1045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1046     { WM_MOVE, sent|defwinproc },
1047     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1048     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1049     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1050     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1051     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1052     { WM_GETTEXT, sent|optional },
1053     { 0 }
1054 };
1055 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1056 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1057     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1058     { 0 }
1059 };
1060 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1061 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1062     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1063     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1064     { WM_NCCALCSIZE, sent|wparam, 1 },
1065     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1066     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1067     { WM_MOVE, sent|defwinproc },
1068     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1069     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1070     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1071     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1072     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1073     { WM_GETTEXT, sent|optional },
1074     { 0 }
1075 };
1076 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1077 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1078     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1079     { 0 }
1080 };
1081 /* ShowWindow(SW_SHOW) for child with invisible parent */
1082 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1083     { WM_SHOWWINDOW, sent|wparam, 1 },
1084     { 0 }
1085 };
1086 /* ShowWindow(SW_HIDE) for child with invisible parent */
1087 static const struct message WmHideChildInvisibleParentSeq[] = {
1088     { WM_SHOWWINDOW, sent|wparam, 0 },
1089     { 0 }
1090 };
1091 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1092 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1093     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1094     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1095     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1096     { 0 }
1097 };
1098 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1099 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1100     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1101     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1102     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1103     { 0 }
1104 };
1105 /* DestroyWindow for a visible child window */
1106 static const struct message WmDestroyChildSeq[] = {
1107     { HCBT_DESTROYWND, hook },
1108     { 0x0090, sent|optional },
1109     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1110     { WM_SHOWWINDOW, sent|wparam, 0 },
1111     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1112     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1113     { WM_ERASEBKGND, sent|parent|optional },
1114     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1115     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1116     { WM_KILLFOCUS, sent },
1117     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1118     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1119     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1120     { WM_SETFOCUS, sent|parent },
1121     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1122     { WM_DESTROY, sent },
1123     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1124     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1125     { WM_NCDESTROY, sent },
1126     { 0 }
1127 };
1128 /* DestroyWindow for a visible child window with invisible parent */
1129 static const struct message WmDestroyInvisibleChildSeq[] = {
1130     { HCBT_DESTROYWND, hook },
1131     { 0x0090, sent|optional },
1132     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1133     { WM_SHOWWINDOW, sent|wparam, 0 },
1134     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1135     { WM_DESTROY, sent },
1136     { WM_NCDESTROY, sent },
1137     { 0 }
1138 };
1139 /* Moving the mouse in nonclient area */
1140 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1141     { WM_NCHITTEST, sent },
1142     { WM_SETCURSOR, sent },
1143     { WM_NCMOUSEMOVE, posted },
1144     { 0 }
1145 };
1146 /* Moving the mouse in client area */
1147 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1148     { WM_NCHITTEST, sent },
1149     { WM_SETCURSOR, sent },
1150     { WM_MOUSEMOVE, posted },
1151     { 0 }
1152 };
1153 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1154 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1155     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1156     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1157     { WM_GETMINMAXINFO, sent|defwinproc },
1158     { WM_ENTERSIZEMOVE, sent|defwinproc },
1159     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1160     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1161     { WM_MOVE, sent|defwinproc },
1162     { WM_EXITSIZEMOVE, sent|defwinproc },
1163     { 0 }
1164 };
1165 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1166 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1167     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1168     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1169     { WM_GETMINMAXINFO, sent|defwinproc },
1170     { WM_ENTERSIZEMOVE, sent|defwinproc },
1171     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1172     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1173     { WM_GETMINMAXINFO, sent|defwinproc },
1174     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1175     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1176     { WM_GETTEXT, sent|defwinproc },
1177     { WM_ERASEBKGND, sent|defwinproc },
1178     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1179     { WM_MOVE, sent|defwinproc },
1180     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1181     { WM_EXITSIZEMOVE, sent|defwinproc },
1182     { 0 }
1183 };
1184 /* Resizing child window with MoveWindow (32) */
1185 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1186     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1187     { WM_NCCALCSIZE, sent|wparam, 1 },
1188     { WM_ERASEBKGND, sent|parent|optional },
1189     { WM_ERASEBKGND, sent|optional },
1190     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1191     { WM_MOVE, sent|defwinproc },
1192     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1193     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1194     { 0 }
1195 };
1196 /* Clicking on inactive button */
1197 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1198     { WM_NCHITTEST, sent },
1199     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1200     { WM_MOUSEACTIVATE, sent },
1201     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1202     { WM_SETCURSOR, sent },
1203     { WM_SETCURSOR, sent|parent|defwinproc },
1204     { WM_LBUTTONDOWN, posted },
1205     { WM_KILLFOCUS, posted|parent },
1206     { WM_SETFOCUS, posted },
1207     { WM_CTLCOLORBTN, posted|parent },
1208     { BM_SETSTATE, posted },
1209     { WM_CTLCOLORBTN, posted|parent },
1210     { WM_LBUTTONUP, posted },
1211     { BM_SETSTATE, posted },
1212     { WM_CTLCOLORBTN, posted|parent },
1213     { WM_COMMAND, posted|parent },
1214     { 0 }
1215 };
1216 /* Reparenting a button (16/32) */
1217 /* The last child (button) reparented gets topmost for its new parent. */
1218 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1219     { WM_SHOWWINDOW, sent|wparam, 0 },
1220     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1221     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1222     { WM_ERASEBKGND, sent|parent },
1223     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1224     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1225     { WM_CHILDACTIVATE, sent },
1226     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1227     { WM_MOVE, sent|defwinproc },
1228     { WM_SHOWWINDOW, sent|wparam, 1 },
1229     { 0 }
1230 };
1231 /* Creation of a custom dialog (32) */
1232 static const struct message WmCreateCustomDialogSeq[] = {
1233     { HCBT_CREATEWND, hook },
1234     { WM_GETMINMAXINFO, sent },
1235     { WM_NCCREATE, sent },
1236     { WM_NCCALCSIZE, sent|wparam, 0 },
1237     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1238     { WM_CREATE, sent },
1239     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1240     { WM_NOTIFYFORMAT, sent|optional },
1241     { WM_QUERYUISTATE, sent|optional },
1242     { WM_WINDOWPOSCHANGING, sent|optional },
1243     { WM_GETMINMAXINFO, sent|optional },
1244     { WM_NCCALCSIZE, sent|optional },
1245     { WM_WINDOWPOSCHANGED, sent|optional },
1246     { WM_SHOWWINDOW, sent|wparam, 1 },
1247     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1248     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1249     { HCBT_ACTIVATE, hook },
1250     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1251
1252
1253     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1254
1255     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1256
1257     { WM_NCACTIVATE, sent },
1258     { WM_GETTEXT, sent|optional|defwinproc },
1259     { WM_GETTEXT, sent|optional|defwinproc },
1260     { WM_GETTEXT, sent|optional|defwinproc },
1261     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1262     { WM_ACTIVATE, sent|wparam, 1 },
1263     { WM_GETTEXT, sent|optional },
1264     { WM_KILLFOCUS, sent|parent },
1265     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1266     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1267     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1268     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1269     { WM_SETFOCUS, sent },
1270     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1271     { WM_NCPAINT, sent|wparam, 1 },
1272     { WM_GETTEXT, sent|optional|defwinproc },
1273     { WM_GETTEXT, sent|optional|defwinproc },
1274     { WM_ERASEBKGND, sent },
1275     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1276     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1277     { WM_GETTEXT, sent|optional },
1278     { WM_GETTEXT, sent|optional },
1279     { WM_NCCALCSIZE, sent|optional },
1280     { WM_NCPAINT, sent|optional },
1281     { WM_GETTEXT, sent|optional|defwinproc },
1282     { WM_GETTEXT, sent|optional|defwinproc },
1283     { WM_ERASEBKGND, sent|optional },
1284     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1285     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1286     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1287     { WM_MOVE, sent },
1288     { 0 }
1289 };
1290 /* Calling EndDialog for a custom dialog (32) */
1291 static const struct message WmEndCustomDialogSeq[] = {
1292     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1293     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1294     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1295     { WM_GETTEXT, sent|optional },
1296     { HCBT_ACTIVATE, hook },
1297     { WM_NCACTIVATE, sent|wparam, 0 },
1298     { WM_GETTEXT, sent|optional|defwinproc },
1299     { WM_GETTEXT, sent|optional|defwinproc },
1300     { WM_ACTIVATE, sent|wparam, 0 },
1301     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1302     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1303     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1304     { WM_GETTEXT, sent|optional|defwinproc },
1305     { WM_GETTEXT, sent|optional|defwinproc },
1306     { HCBT_SETFOCUS, hook },
1307     { WM_KILLFOCUS, sent },
1308     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1309     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1310     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1311     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1312     { WM_SETFOCUS, sent|parent|defwinproc },
1313     { 0 }
1314 };
1315 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1316 static const struct message WmShowCustomDialogSeq[] = {
1317     { WM_SHOWWINDOW, sent|wparam, 1 },
1318     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1319     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1320     { HCBT_ACTIVATE, hook },
1321     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1322
1323     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1324
1325     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1326     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1327     { WM_NCACTIVATE, sent },
1328     { WM_ACTIVATE, sent|wparam, 1 },
1329     { WM_GETTEXT, sent|optional },
1330
1331     { WM_KILLFOCUS, sent|parent },
1332     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1333     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1334     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1335     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1336     { WM_SETFOCUS, sent },
1337     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1338     { WM_NCPAINT, sent|wparam, 1 },
1339     { WM_ERASEBKGND, sent },
1340     { WM_CTLCOLORDLG, sent|defwinproc },
1341     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1342     { 0 }
1343 };
1344 /* Creation and destruction of a modal dialog (32) */
1345 static const struct message WmModalDialogSeq[] = {
1346     { WM_CANCELMODE, sent|parent },
1347     { HCBT_SETFOCUS, hook },
1348     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1349     { WM_KILLFOCUS, sent|parent },
1350     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1351     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1352     { WM_ENABLE, sent|parent|wparam, 0 },
1353     { HCBT_CREATEWND, hook },
1354     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1355     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1356     { WM_SETFONT, sent },
1357     { WM_INITDIALOG, sent },
1358     { WM_CHANGEUISTATE, sent|optional },
1359     { WM_UPDATEUISTATE, sent|optional },
1360     { WM_SHOWWINDOW, sent },
1361     { HCBT_ACTIVATE, hook },
1362     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1363     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1364     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1365     { WM_NCACTIVATE, sent },
1366     { WM_GETTEXT, sent|optional },
1367     { WM_ACTIVATE, sent|wparam, 1 },
1368     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1369     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1370     { WM_NCPAINT, sent|optional },
1371     { WM_GETTEXT, sent|optional },
1372     { WM_ERASEBKGND, sent|optional },
1373     { WM_CTLCOLORDLG, sent|optional },
1374     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1375     { WM_GETTEXT, sent|optional },
1376     { WM_NCCALCSIZE, sent|optional },
1377     { WM_NCPAINT, sent|optional },
1378     { WM_GETTEXT, sent|optional },
1379     { WM_ERASEBKGND, sent|optional },
1380     { WM_CTLCOLORDLG, sent|optional },
1381     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1382     { WM_PAINT, sent|optional },
1383     { WM_CTLCOLORBTN, sent|optional },
1384     { WM_GETTITLEBARINFOEX, sent|optional },
1385     { WM_ENTERIDLE, sent|parent|optional },
1386     { WM_ENTERIDLE, sent|parent|optional },
1387     { WM_ENTERIDLE, sent|parent|optional },
1388     { WM_ENTERIDLE, sent|parent|optional },
1389     { WM_ENTERIDLE, sent|parent|optional },
1390     { WM_ENTERIDLE, sent|parent|optional },
1391     { WM_ENTERIDLE, sent|parent|optional },
1392     { WM_ENTERIDLE, sent|parent|optional },
1393     { WM_ENTERIDLE, sent|parent|optional },
1394     { WM_ENTERIDLE, sent|parent|optional },
1395     { WM_ENTERIDLE, sent|parent|optional },
1396     { WM_ENTERIDLE, sent|parent|optional },
1397     { WM_ENTERIDLE, sent|parent|optional },
1398     { WM_ENTERIDLE, sent|parent|optional },
1399     { WM_ENTERIDLE, sent|parent|optional },
1400     { WM_ENTERIDLE, sent|parent|optional },
1401     { WM_ENTERIDLE, sent|parent|optional },
1402     { WM_ENTERIDLE, sent|parent|optional },
1403     { WM_ENTERIDLE, sent|parent|optional },
1404     { WM_ENTERIDLE, sent|parent|optional },
1405     { WM_TIMER, sent },
1406     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1407     { WM_ENABLE, sent|parent|wparam, 1 },
1408     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1409     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1410     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1411     { WM_GETTEXT, sent|optional },
1412     { HCBT_ACTIVATE, hook },
1413     { WM_NCACTIVATE, sent|wparam, 0 },
1414     { WM_GETTEXT, sent|optional },
1415     { WM_ACTIVATE, sent|wparam, 0 },
1416     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1417     { WM_WINDOWPOSCHANGING, sent|optional },
1418     { WM_WINDOWPOSCHANGED, sent|optional },
1419     { HCBT_SETFOCUS, hook },
1420     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1421     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1422     { WM_SETFOCUS, sent|parent|defwinproc },
1423     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1424     { HCBT_DESTROYWND, hook },
1425     { 0x0090, sent|optional },
1426     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1427     { WM_DESTROY, sent },
1428     { WM_NCDESTROY, sent },
1429     { 0 }
1430 };
1431 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1432 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1433     /* (inside dialog proc, handling WM_INITDIALOG) */
1434     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1435     { WM_NCCALCSIZE, sent },
1436     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1437     { WM_GETTEXT, sent|defwinproc },
1438     { WM_ACTIVATE, sent|parent|wparam, 0 },
1439     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1440     { WM_WINDOWPOSCHANGING, sent|parent },
1441     { WM_NCACTIVATE, sent|wparam, 1 },
1442     { WM_ACTIVATE, sent|wparam, 1 },
1443     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1444     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1445     /* (setting focus) */
1446     { WM_SHOWWINDOW, sent|wparam, 1 },
1447     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1448     { WM_NCPAINT, sent },
1449     { WM_GETTEXT, sent|defwinproc },
1450     { WM_ERASEBKGND, sent },
1451     { WM_CTLCOLORDLG, sent|defwinproc },
1452     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1453     { WM_PAINT, sent },
1454     /* (bunch of WM_CTLCOLOR* for each control) */
1455     { WM_PAINT, sent|parent },
1456     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1457     { WM_SETCURSOR, sent|parent },
1458     { 0 }
1459 };
1460 /* SetMenu for NonVisible windows with size change*/
1461 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1462     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1463     { WM_NCCALCSIZE, sent|wparam, 1 },
1464     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1465     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1466     { WM_MOVE, sent|defwinproc },
1467     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1468     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1469     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1470     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1471     { WM_GETTEXT, sent|optional },
1472     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1473     { 0 }
1474 };
1475 /* SetMenu for NonVisible windows with no size change */
1476 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1477     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1478     { WM_NCCALCSIZE, sent|wparam, 1 },
1479     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1480     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1481     { 0 }
1482 };
1483 /* SetMenu for Visible windows with size change */
1484 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1485     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1486     { WM_NCCALCSIZE, sent|wparam, 1 },
1487     { 0x0093, sent|defwinproc|optional },
1488     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1489     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1490     { 0x0093, sent|defwinproc|optional },
1491     { 0x0093, sent|defwinproc|optional },
1492     { 0x0091, sent|defwinproc|optional },
1493     { 0x0092, sent|defwinproc|optional },
1494     { WM_GETTEXT, sent|defwinproc|optional },
1495     { WM_ERASEBKGND, sent|optional },
1496     { WM_ACTIVATE, sent|optional },
1497     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1498     { WM_MOVE, sent|defwinproc },
1499     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1500     { 0x0093, sent|optional },
1501     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1502     { 0x0093, sent|defwinproc|optional },
1503     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1504     { 0x0093, sent|defwinproc|optional },
1505     { 0x0093, sent|defwinproc|optional },
1506     { 0x0091, sent|defwinproc|optional },
1507     { 0x0092, sent|defwinproc|optional },
1508     { WM_ERASEBKGND, sent|optional },
1509     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1510     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1511     { 0 }
1512 };
1513 /* SetMenu for Visible windows with no size change */
1514 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1516     { WM_NCCALCSIZE, sent|wparam, 1 },
1517     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1518     { WM_GETTEXT, sent|defwinproc|optional },
1519     { WM_ERASEBKGND, sent|optional },
1520     { WM_ACTIVATE, sent|optional },
1521     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1522     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1523     { 0 }
1524 };
1525 /* DrawMenuBar for a visible window */
1526 static const struct message WmDrawMenuBarSeq[] =
1527 {
1528     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1529     { WM_NCCALCSIZE, sent|wparam, 1 },
1530     { 0x0093, sent|defwinproc|optional },
1531     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1532     { 0x0093, sent|defwinproc|optional },
1533     { 0x0093, sent|defwinproc|optional },
1534     { 0x0091, sent|defwinproc|optional },
1535     { 0x0092, sent|defwinproc|optional },
1536     { WM_GETTEXT, sent|defwinproc|optional },
1537     { WM_ERASEBKGND, sent|optional },
1538     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1539     { 0x0093, sent|optional },
1540     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1541     { 0 }
1542 };
1543
1544 static const struct message WmSetRedrawFalseSeq[] =
1545 {
1546     { WM_SETREDRAW, sent|wparam, 0 },
1547     { 0 }
1548 };
1549
1550 static const struct message WmSetRedrawTrueSeq[] =
1551 {
1552     { WM_SETREDRAW, sent|wparam, 1 },
1553     { 0 }
1554 };
1555
1556 static const struct message WmEnableWindowSeq_1[] =
1557 {
1558     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1559     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1560     { HCBT_SETFOCUS, hook|optional },
1561     { WM_KILLFOCUS, sent|optional },
1562     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1563     { 0 }
1564 };
1565
1566 static const struct message WmEnableWindowSeq_2[] =
1567 {
1568     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1569     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1570     { 0 }
1571 };
1572
1573 static const struct message WmGetScrollRangeSeq[] =
1574 {
1575     { SBM_GETRANGE, sent },
1576     { 0 }
1577 };
1578 static const struct message WmGetScrollInfoSeq[] =
1579 {
1580     { SBM_GETSCROLLINFO, sent },
1581     { 0 }
1582 };
1583 static const struct message WmSetScrollRangeSeq[] =
1584 {
1585     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1586        sends SBM_SETSCROLLINFO.
1587      */
1588     { SBM_SETSCROLLINFO, sent },
1589     { 0 }
1590 };
1591 /* SetScrollRange for a window without a non-client area */
1592 static const struct message WmSetScrollRangeHSeq_empty[] =
1593 {
1594     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1595     { 0 }
1596 };
1597 static const struct message WmSetScrollRangeVSeq_empty[] =
1598 {
1599     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1600     { 0 }
1601 };
1602 static const struct message WmSetScrollRangeHVSeq[] =
1603 {
1604     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1605     { WM_NCCALCSIZE, sent|wparam, 1 },
1606     { WM_GETTEXT, sent|defwinproc|optional },
1607     { WM_ERASEBKGND, sent|optional },
1608     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1609     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1610     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1611     { 0 }
1612 };
1613 /* SetScrollRange for a window with a non-client area */
1614 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1615 {
1616     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1617     { WM_NCCALCSIZE, sent|wparam, 1 },
1618     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1619     { WM_NCPAINT, sent|optional },
1620     { WM_STYLECHANGING, sent|defwinproc|optional },
1621     { WM_STYLECHANGED, sent|defwinproc|optional },
1622     { WM_STYLECHANGING, sent|defwinproc|optional },
1623     { WM_STYLECHANGED, sent|defwinproc|optional },
1624     { WM_STYLECHANGING, sent|defwinproc|optional },
1625     { WM_STYLECHANGED, sent|defwinproc|optional },
1626     { WM_STYLECHANGING, sent|defwinproc|optional },
1627     { WM_STYLECHANGED, sent|defwinproc|optional },
1628     { WM_GETTEXT, sent|defwinproc|optional },
1629     { WM_GETTEXT, sent|defwinproc|optional },
1630     { WM_ERASEBKGND, sent|optional },
1631     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1633     { WM_SIZE, sent|defwinproc|optional },
1634     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1635     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1636     { WM_GETTEXT, sent|optional },
1637     { WM_GETTEXT, sent|optional },
1638     { WM_GETTEXT, sent|optional },
1639     { WM_GETTEXT, sent|optional },
1640     { 0 }
1641 };
1642 /* test if we receive the right sequence of messages */
1643 /* after calling ShowWindow( SW_SHOWNA) */
1644 static const struct message WmSHOWNAChildInvisParInvis[] = {
1645     { WM_SHOWWINDOW, sent|wparam, 1 },
1646     { 0 }
1647 };
1648 static const struct message WmSHOWNAChildVisParInvis[] = {
1649     { WM_SHOWWINDOW, sent|wparam, 1 },
1650     { 0 }
1651 };
1652 static const struct message WmSHOWNAChildVisParVis[] = {
1653     { WM_SHOWWINDOW, sent|wparam, 1 },
1654     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1655     { 0 }
1656 };
1657 static const struct message WmSHOWNAChildInvisParVis[] = {
1658     { WM_SHOWWINDOW, sent|wparam, 1 },
1659     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1660     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1661     { WM_ERASEBKGND, sent|optional },
1662     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1663     { 0 }
1664 };
1665 static const struct message WmSHOWNATopVisible[] = {
1666     { WM_SHOWWINDOW, sent|wparam, 1 },
1667     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1668     { WM_NCPAINT, sent|wparam|optional, 1 },
1669     { WM_GETTEXT, sent|defwinproc|optional },
1670     { WM_ERASEBKGND, sent|optional },
1671     { WM_WINDOWPOSCHANGED, sent|optional },
1672     { 0 }
1673 };
1674 static const struct message WmSHOWNATopInvisible[] = {
1675     { WM_NOTIFYFORMAT, sent|optional },
1676     { WM_QUERYUISTATE, sent|optional },
1677     { WM_WINDOWPOSCHANGING, sent|optional },
1678     { WM_GETMINMAXINFO, sent|optional },
1679     { WM_NCCALCSIZE, sent|optional },
1680     { WM_WINDOWPOSCHANGED, sent|optional },
1681     { WM_SHOWWINDOW, sent|wparam, 1 },
1682     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1683     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1684     { WM_NCPAINT, sent|wparam|optional, 1 },
1685     { WM_GETTEXT, sent|defwinproc|optional },
1686     { WM_ERASEBKGND, sent|optional },
1687     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1688     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1689     { WM_NCPAINT, sent|wparam|optional, 1 },
1690     { WM_ERASEBKGND, sent|optional },
1691     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1692     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1693     { WM_MOVE, sent },
1694     { 0 }
1695 };
1696
1697 static int after_end_dialog, test_def_id;
1698 static int sequence_cnt, sequence_size;
1699 static struct recvd_message* sequence;
1700 static int log_all_parent_messages;
1701 static int paint_loop_done;
1702
1703 /* user32 functions */
1704 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1705 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1706 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1707 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1708 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1709 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1710 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1711 /* kernel32 functions */
1712 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1713
1714 static void init_procs(void)
1715 {
1716     HMODULE user32 = GetModuleHandleA("user32.dll");
1717     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1718
1719 #define GET_PROC(dll, func) \
1720     p ## func = (void*)GetProcAddress(dll, #func); \
1721     if(!p ## func) { \
1722       trace("GetProcAddress(%s) failed\n", #func); \
1723     }
1724
1725     GET_PROC(user32, GetAncestor)
1726     GET_PROC(user32, GetMenuInfo)
1727     GET_PROC(user32, NotifyWinEvent)
1728     GET_PROC(user32, SetMenuInfo)
1729     GET_PROC(user32, SetWinEventHook)
1730     GET_PROC(user32, TrackMouseEvent)
1731     GET_PROC(user32, UnhookWinEvent)
1732
1733     GET_PROC(kernel32, GetCPInfoExA)
1734
1735 #undef GET_PROC
1736 }
1737
1738 static const char *get_winpos_flags(UINT flags)
1739 {
1740     static char buffer[300];
1741
1742     buffer[0] = 0;
1743 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1744     DUMP( SWP_SHOWWINDOW );
1745     DUMP( SWP_HIDEWINDOW );
1746     DUMP( SWP_NOACTIVATE );
1747     DUMP( SWP_FRAMECHANGED );
1748     DUMP( SWP_NOCOPYBITS );
1749     DUMP( SWP_NOOWNERZORDER );
1750     DUMP( SWP_NOSENDCHANGING );
1751     DUMP( SWP_DEFERERASE );
1752     DUMP( SWP_ASYNCWINDOWPOS );
1753     DUMP( SWP_NOZORDER );
1754     DUMP( SWP_NOREDRAW );
1755     DUMP( SWP_NOSIZE );
1756     DUMP( SWP_NOMOVE );
1757     DUMP( SWP_NOCLIENTSIZE );
1758     DUMP( SWP_NOCLIENTMOVE );
1759     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1760     return buffer + 1;
1761 #undef DUMP
1762 }
1763
1764 static BOOL ignore_message( UINT message )
1765 {
1766     /* these are always ignored */
1767     return (message >= 0xc000 ||
1768             message == WM_GETICON ||
1769             message == WM_GETOBJECT ||
1770             message == WM_TIMECHANGE ||
1771             message == WM_DEVICECHANGE);
1772 }
1773
1774
1775 #define add_message(msg) add_message_(__LINE__,msg);
1776 static void add_message_(int line, const struct recvd_message *msg)
1777 {
1778     struct recvd_message *seq;
1779
1780     if (!sequence) 
1781     {
1782         sequence_size = 10;
1783         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1784     }
1785     if (sequence_cnt == sequence_size) 
1786     {
1787         sequence_size *= 2;
1788         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1789     }
1790     assert(sequence);
1791
1792     seq = &sequence[sequence_cnt];
1793     seq->hwnd = msg->hwnd;
1794     seq->message = msg->message;
1795     seq->flags = msg->flags;
1796     seq->wParam = msg->wParam;
1797     seq->lParam = msg->lParam;
1798     seq->line   = line;
1799     seq->descr  = msg->descr;
1800     seq->output[0] = 0;
1801
1802     if (msg->descr)
1803     {
1804         if (msg->flags & hook)
1805         {
1806             static const char * const CBT_code_name[10] =
1807             {
1808                 "HCBT_MOVESIZE",
1809                 "HCBT_MINMAX",
1810                 "HCBT_QS",
1811                 "HCBT_CREATEWND",
1812                 "HCBT_DESTROYWND",
1813                 "HCBT_ACTIVATE",
1814                 "HCBT_CLICKSKIPPED",
1815                 "HCBT_KEYSKIPPED",
1816                 "HCBT_SYSCOMMAND",
1817                 "HCBT_SETFOCUS"
1818             };
1819             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1820
1821             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1822                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1823         }
1824         else if (msg->flags & winevent_hook)
1825         {
1826             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1827                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1828         }
1829         else
1830         {
1831             switch (msg->message)
1832             {
1833             case WM_WINDOWPOSCHANGING:
1834             case WM_WINDOWPOSCHANGED:
1835             {
1836                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1837
1838                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1839                           msg->descr, msg->hwnd,
1840                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1841                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1842                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1843                           get_winpos_flags(winpos->flags) );
1844
1845                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1846                  * in the high word for internal purposes
1847                  */
1848                 seq->wParam = winpos->flags & 0xffff;
1849                 /* We are not interested in the flags that don't match under XP and Win9x */
1850                 seq->wParam &= ~SWP_NOZORDER;
1851                 break;
1852             }
1853
1854             case WM_DRAWITEM:
1855             {
1856                 DRAW_ITEM_STRUCT di;
1857                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1858
1859                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1860                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1861                          dis->itemID, dis->itemAction, dis->itemState);
1862
1863                 di.u.lp = 0;
1864                 di.u.item.type = dis->CtlType;
1865                 di.u.item.ctl_id = dis->CtlID;
1866                 di.u.item.item_id = dis->itemID;
1867                 di.u.item.action = dis->itemAction;
1868                 di.u.item.state = dis->itemState;
1869
1870                 seq->lParam = di.u.lp;
1871                 break;
1872             }
1873             default:
1874                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1875                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1876                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1877             }
1878             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1879                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1880         }
1881     }
1882
1883     sequence_cnt++;
1884 }
1885
1886 /* try to make sure pending X events have been processed before continuing */
1887 static void flush_events(void)
1888 {
1889     MSG msg;
1890     int diff = 200;
1891     int min_timeout = 100;
1892     DWORD time = GetTickCount() + diff;
1893
1894     while (diff > 0)
1895     {
1896         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1897         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1898         diff = time - GetTickCount();
1899     }
1900 }
1901
1902 static void flush_sequence(void)
1903 {
1904     HeapFree(GetProcessHeap(), 0, sequence);
1905     sequence = 0;
1906     sequence_cnt = sequence_size = 0;
1907 }
1908
1909 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1910 {
1911     const struct recvd_message *actual = sequence;
1912     unsigned int count = 0;
1913
1914     trace_(file, line)("Failed sequence %s:\n", context );
1915     while (expected->message && actual->message)
1916     {
1917         if (actual->output[0])
1918         {
1919             if (expected->flags & hook)
1920             {
1921                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1922                                     count, expected->message, actual->output );
1923             }
1924             else if (expected->flags & winevent_hook)
1925             {
1926                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1927                                     count, expected->message, actual->output );
1928             }
1929             else
1930             {
1931                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1932                                     count, expected->message, actual->output );
1933             }
1934         }
1935
1936         if (expected->message == actual->message)
1937         {
1938             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1939                 (expected->flags & optional))
1940             {
1941                 /* don't match messages if their defwinproc status differs */
1942                 expected++;
1943             }
1944             else
1945             {
1946                 expected++;
1947                 actual++;
1948             }
1949         }
1950         /* silently drop winevent messages if there is no support for them */
1951         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1952             expected++;
1953         else
1954         {
1955             expected++;
1956             actual++;
1957         }
1958         count++;
1959     }
1960
1961     /* optional trailing messages */
1962     while (expected->message && ((expected->flags & optional) ||
1963             ((expected->flags & winevent_hook) && !hEvent_hook)))
1964     {
1965         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1966         expected++;
1967         count++;
1968     }
1969
1970     if (expected->message)
1971     {
1972         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1973         return;
1974     }
1975
1976     while (actual->message && actual->output[0])
1977     {
1978         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
1979         actual++;
1980         count++;
1981     }
1982 }
1983
1984 #define ok_sequence( exp, contx, todo) \
1985         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1986
1987
1988 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
1989                          const char *file, int line)
1990 {
1991     static const struct recvd_message end_of_sequence;
1992     const struct message *expected = expected_list;
1993     const struct recvd_message *actual;
1994     int failcount = 0, dump = 0;
1995     unsigned int count = 0;
1996
1997     add_message(&end_of_sequence);
1998
1999     actual = sequence;
2000
2001     while (expected->message && actual->message)
2002     {
2003         if (expected->message == actual->message)
2004         {
2005             if (expected->flags & wparam)
2006             {
2007                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2008                 {
2009                     todo_wine {
2010                         failcount ++;
2011                         if (strcmp(winetest_platform, "wine")) dump++;
2012                         ok_( file, line) (FALSE,
2013                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2014                             context, count, expected->message, expected->wParam, actual->wParam);
2015                     }
2016                 }
2017                 else
2018                 {
2019                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2020                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2021                                      context, count, expected->message, expected->wParam, actual->wParam);
2022                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2023                 }
2024
2025             }
2026             if (expected->flags & lparam)
2027             {
2028                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2029                 {
2030                     todo_wine {
2031                         failcount ++;
2032                         if (strcmp(winetest_platform, "wine")) dump++;
2033                         ok_( file, line) (FALSE,
2034                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2035                             context, count, expected->message, expected->lParam, actual->lParam);
2036                     }
2037                 }
2038                 else
2039                 {
2040                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2041                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2042                                      context, count, expected->message, expected->lParam, actual->lParam);
2043                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2044                 }
2045             }
2046             if ((expected->flags & optional) &&
2047                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2048             {
2049                 /* don't match optional messages if their defwinproc or parent status differs */
2050                 expected++;
2051                 count++;
2052                 continue;
2053             }
2054             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2055             {
2056                     todo_wine {
2057                         failcount ++;
2058                         if (strcmp(winetest_platform, "wine")) dump++;
2059                         ok_( file, line) (FALSE,
2060                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2061                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2062                     }
2063             }
2064             else
2065             {
2066                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2067                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2068                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2069                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2070             }
2071
2072             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2073                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2074                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2075             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2076
2077             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2078                 "%s: %u: the msg 0x%04x should have been %s\n",
2079                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2080             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2081
2082             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2083                 "%s: %u: the msg 0x%04x was expected in %s\n",
2084                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2085             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2086
2087             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2088                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2089                 context, count, expected->message);
2090             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2091
2092             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2093                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2094                 context, count, expected->message);
2095             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2096
2097             expected++;
2098             actual++;
2099         }
2100         /* silently drop hook messages if there is no support for them */
2101         else if ((expected->flags & optional) ||
2102                  ((expected->flags & hook) && !hCBT_hook) ||
2103                  ((expected->flags & winevent_hook) && !hEvent_hook))
2104             expected++;
2105         else if (todo)
2106         {
2107             failcount++;
2108             todo_wine {
2109                 if (strcmp(winetest_platform, "wine")) dump++;
2110                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2111                                   context, count, expected->message, actual->message);
2112             }
2113             goto done;
2114         }
2115         else
2116         {
2117             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2118                               context, count, expected->message, actual->message);
2119             dump++;
2120             expected++;
2121             actual++;
2122         }
2123         count++;
2124     }
2125
2126     /* skip all optional trailing messages */
2127     while (expected->message && ((expected->flags & optional) ||
2128                                  ((expected->flags & hook) && !hCBT_hook) ||
2129                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2130         expected++;
2131
2132     if (todo)
2133     {
2134         todo_wine {
2135             if (expected->message || actual->message) {
2136                 failcount++;
2137                 if (strcmp(winetest_platform, "wine")) dump++;
2138                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2139                                   context, count, expected->message, actual->message);
2140             }
2141         }
2142     }
2143     else
2144     {
2145         if (expected->message || actual->message)
2146         {
2147             dump++;
2148             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2149                               context, count, expected->message, actual->message);
2150         }
2151     }
2152     if( todo && !failcount) /* succeeded yet marked todo */
2153         todo_wine {
2154             if (!strcmp(winetest_platform, "wine")) dump++;
2155             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2156         }
2157
2158 done:
2159     if (dump) dump_sequence(expected_list, context, file, line);
2160     flush_sequence();
2161 }
2162
2163 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2164
2165 /******************************** MDI test **********************************/
2166
2167 /* CreateWindow for MDI frame window, initially visible */
2168 static const struct message WmCreateMDIframeSeq[] = {
2169     { HCBT_CREATEWND, hook },
2170     { WM_GETMINMAXINFO, sent },
2171     { WM_NCCREATE, sent },
2172     { WM_NCCALCSIZE, sent|wparam, 0 },
2173     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2174     { WM_CREATE, sent },
2175     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2176     { WM_NOTIFYFORMAT, sent|optional },
2177     { WM_QUERYUISTATE, sent|optional },
2178     { WM_WINDOWPOSCHANGING, sent|optional },
2179     { WM_GETMINMAXINFO, sent|optional },
2180     { WM_NCCALCSIZE, sent|optional },
2181     { WM_WINDOWPOSCHANGED, sent|optional },
2182     { WM_SHOWWINDOW, sent|wparam, 1 },
2183     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2184     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2185     { HCBT_ACTIVATE, hook },
2186     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2187     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2188     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2189     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2190     { WM_NCACTIVATE, sent },
2191     { WM_GETTEXT, sent|defwinproc|optional },
2192     { WM_ACTIVATE, sent|wparam, 1 },
2193     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2194     { HCBT_SETFOCUS, hook },
2195     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2196     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2197     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2198     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2199     /* Win9x adds SWP_NOZORDER below */
2200     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2201     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2202     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2203     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2204     { WM_MOVE, sent },
2205     { 0 }
2206 };
2207 /* DestroyWindow for MDI frame window, initially visible */
2208 static const struct message WmDestroyMDIframeSeq[] = {
2209     { HCBT_DESTROYWND, hook },
2210     { 0x0090, sent|optional },
2211     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2212     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2213     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2214     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2215     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2216     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2217     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2218     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2219     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2220     { WM_DESTROY, sent },
2221     { WM_NCDESTROY, sent },
2222     { 0 }
2223 };
2224 /* CreateWindow for MDI client window, initially visible */
2225 static const struct message WmCreateMDIclientSeq[] = {
2226     { HCBT_CREATEWND, hook },
2227     { WM_NCCREATE, sent },
2228     { WM_NCCALCSIZE, sent|wparam, 0 },
2229     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2230     { WM_CREATE, sent },
2231     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2232     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2233     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2234     { WM_MOVE, sent },
2235     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2236     { WM_SHOWWINDOW, sent|wparam, 1 },
2237     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2238     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2239     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2240     { 0 }
2241 };
2242 /* ShowWindow(SW_SHOW) for MDI client window */
2243 static const struct message WmShowMDIclientSeq[] = {
2244     { WM_SHOWWINDOW, sent|wparam, 1 },
2245     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2246     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2247     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2248     { 0 }
2249 };
2250 /* ShowWindow(SW_HIDE) for MDI client window */
2251 static const struct message WmHideMDIclientSeq[] = {
2252     { WM_SHOWWINDOW, sent|wparam, 0 },
2253     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2254     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2255     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2256     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2257     { 0 }
2258 };
2259 /* DestroyWindow for MDI client window, initially visible */
2260 static const struct message WmDestroyMDIclientSeq[] = {
2261     { HCBT_DESTROYWND, hook },
2262     { 0x0090, sent|optional },
2263     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2264     { WM_SHOWWINDOW, sent|wparam, 0 },
2265     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2266     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2267     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2268     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2269     { WM_DESTROY, sent },
2270     { WM_NCDESTROY, sent },
2271     { 0 }
2272 };
2273 /* CreateWindow for MDI child window, initially visible */
2274 static const struct message WmCreateMDIchildVisibleSeq[] = {
2275     { HCBT_CREATEWND, hook },
2276     { WM_NCCREATE, sent }, 
2277     { WM_NCCALCSIZE, sent|wparam, 0 },
2278     { WM_CREATE, sent },
2279     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2280     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2281     { WM_MOVE, sent },
2282     /* Win2k sends wparam set to
2283      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2284      * while Win9x doesn't bother to set child window id according to
2285      * CLIENTCREATESTRUCT.idFirstChild
2286      */
2287     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2288     { WM_SHOWWINDOW, sent|wparam, 1 },
2289     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2290     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2291     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2292     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2293     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2294     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2295     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2296
2297     /* Win9x: message sequence terminates here. */
2298
2299     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2300     { HCBT_SETFOCUS, hook }, /* in MDI client */
2301     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2302     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2303     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2304     { WM_SETFOCUS, sent }, /* in MDI client */
2305     { HCBT_SETFOCUS, hook },
2306     { WM_KILLFOCUS, sent }, /* in MDI client */
2307     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2308     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2309     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2310     { WM_SETFOCUS, sent|defwinproc },
2311     { WM_MDIACTIVATE, sent|defwinproc },
2312     { 0 }
2313 };
2314 /* CreateWindow for MDI child window with invisible parent */
2315 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2316     { HCBT_CREATEWND, hook },
2317     { WM_GETMINMAXINFO, sent },
2318     { WM_NCCREATE, sent }, 
2319     { WM_NCCALCSIZE, sent|wparam, 0 },
2320     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2321     { WM_CREATE, sent },
2322     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2323     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2324     { WM_MOVE, sent },
2325     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2326     { WM_SHOWWINDOW, sent|wparam, 1 },
2327     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2328     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2329     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2330     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2331
2332     /* Win9x: message sequence terminates here. */
2333
2334     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2335     { HCBT_SETFOCUS, hook }, /* in MDI client */
2336     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2337     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2338     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2339     { WM_SETFOCUS, sent }, /* in MDI client */
2340     { HCBT_SETFOCUS, hook },
2341     { WM_KILLFOCUS, sent }, /* in MDI client */
2342     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2343     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2344     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2345     { WM_SETFOCUS, sent|defwinproc },
2346     { WM_MDIACTIVATE, sent|defwinproc },
2347     { 0 }
2348 };
2349 /* DestroyWindow for MDI child window, initially visible */
2350 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2351     { HCBT_DESTROYWND, hook },
2352     /* Win2k sends wparam set to
2353      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2354      * while Win9x doesn't bother to set child window id according to
2355      * CLIENTCREATESTRUCT.idFirstChild
2356      */
2357     { 0x0090, sent|optional },
2358     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2359     { WM_SHOWWINDOW, sent|wparam, 0 },
2360     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2361     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2362     { WM_ERASEBKGND, sent|parent|optional },
2363     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2364
2365     /* { WM_DESTROY, sent }
2366      * Win9x: message sequence terminates here.
2367      */
2368
2369     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2370     { WM_KILLFOCUS, sent },
2371     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2372     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2373     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2374     { WM_SETFOCUS, sent }, /* in MDI client */
2375
2376     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2377     { WM_KILLFOCUS, sent }, /* in MDI client */
2378     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2379     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2380     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2381     { WM_SETFOCUS, sent }, /* in MDI client */
2382
2383     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2384
2385     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2386     { WM_KILLFOCUS, sent },
2387     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2388     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2389     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2390     { WM_SETFOCUS, sent }, /* in MDI client */
2391
2392     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2393     { WM_KILLFOCUS, sent }, /* in MDI client */
2394     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2395     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2396     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2397     { WM_SETFOCUS, sent }, /* in MDI client */
2398
2399     { WM_DESTROY, sent },
2400
2401     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2402     { WM_KILLFOCUS, sent },
2403     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2404     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2405     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2406     { WM_SETFOCUS, sent }, /* in MDI client */
2407
2408     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2409     { WM_KILLFOCUS, sent }, /* in MDI client */
2410     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2411     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2412     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2413     { WM_SETFOCUS, sent }, /* in MDI client */
2414
2415     { WM_NCDESTROY, sent },
2416     { 0 }
2417 };
2418 /* CreateWindow for MDI child window, initially invisible */
2419 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2420     { HCBT_CREATEWND, hook },
2421     { WM_NCCREATE, sent }, 
2422     { WM_NCCALCSIZE, sent|wparam, 0 },
2423     { WM_CREATE, sent },
2424     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2425     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2426     { WM_MOVE, sent },
2427     /* Win2k sends wparam set to
2428      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2429      * while Win9x doesn't bother to set child window id according to
2430      * CLIENTCREATESTRUCT.idFirstChild
2431      */
2432     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2433     { 0 }
2434 };
2435 /* DestroyWindow for MDI child window, initially invisible */
2436 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2437     { HCBT_DESTROYWND, hook },
2438     /* Win2k sends wparam set to
2439      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2440      * while Win9x doesn't bother to set child window id according to
2441      * CLIENTCREATESTRUCT.idFirstChild
2442      */
2443     { 0x0090, sent|optional },
2444     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2445     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2446     { WM_DESTROY, sent },
2447     { WM_NCDESTROY, sent },
2448     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2449     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2450     { 0 }
2451 };
2452 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2453 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2454     { HCBT_CREATEWND, hook },
2455     { WM_NCCREATE, sent }, 
2456     { WM_NCCALCSIZE, sent|wparam, 0 },
2457     { WM_CREATE, sent },
2458     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2459     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2460     { WM_MOVE, sent },
2461     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2462     { WM_GETMINMAXINFO, sent },
2463     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2464     { WM_NCCALCSIZE, sent|wparam, 1 },
2465     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2466     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2467      /* in MDI frame */
2468     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2469     { WM_NCCALCSIZE, sent|wparam, 1 },
2470     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2471     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2472     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2473     /* Win2k sends wparam set to
2474      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2475      * while Win9x doesn't bother to set child window id according to
2476      * CLIENTCREATESTRUCT.idFirstChild
2477      */
2478     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2479     { WM_SHOWWINDOW, sent|wparam, 1 },
2480     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2481     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2482     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2483     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2484     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2485     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2486     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2487
2488     /* Win9x: message sequence terminates here. */
2489
2490     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2491     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2492     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2493     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2494     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2495     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2496     { HCBT_SETFOCUS, hook|optional },
2497     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2498     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2499     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2500     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2501     { WM_SETFOCUS, sent|defwinproc|optional },
2502     { WM_MDIACTIVATE, sent|defwinproc|optional },
2503      /* in MDI frame */
2504     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2505     { WM_NCCALCSIZE, sent|wparam, 1 },
2506     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2507     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2508     { 0 }
2509 };
2510 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2511 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2512     /* restore the 1st MDI child */
2513     { WM_SETREDRAW, sent|wparam, 0 },
2514     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2516     { WM_NCCALCSIZE, sent|wparam, 1 },
2517     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2518     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2519     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2520      /* in MDI frame */
2521     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2522     { WM_NCCALCSIZE, sent|wparam, 1 },
2523     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2524     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2525     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2526     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2527     /* create the 2nd MDI child */
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     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2540     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2541     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
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     /* Win2k sends wparam set to
2549      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2550      * while Win9x doesn't bother to set child window id according to
2551      * CLIENTCREATESTRUCT.idFirstChild
2552      */
2553     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2554     { WM_SHOWWINDOW, sent|wparam, 1 },
2555     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2556     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2557     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2558     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2559     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2560     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2561
2562     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2563     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2564
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     { HCBT_SETFOCUS, hook },
2571     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2572     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2573     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2574     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2575     { WM_SETFOCUS, sent }, /* in MDI client */
2576     { HCBT_SETFOCUS, hook },
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      /* in MDI frame */
2585     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2586     { WM_NCCALCSIZE, sent|wparam, 1 },
2587     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2588     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2589     { 0 }
2590 };
2591 /* WM_MDICREATE MDI child window, initially visible and maximized */
2592 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2593     { WM_MDICREATE, sent },
2594     { HCBT_CREATEWND, hook },
2595     { WM_NCCREATE, sent }, 
2596     { WM_NCCALCSIZE, sent|wparam, 0 },
2597     { WM_CREATE, sent },
2598     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2599     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2600     { WM_MOVE, sent },
2601     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2602     { WM_GETMINMAXINFO, sent },
2603     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2604     { WM_NCCALCSIZE, sent|wparam, 1 },
2605     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2606     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2607
2608      /* in MDI frame */
2609     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2610     { WM_NCCALCSIZE, sent|wparam, 1 },
2611     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2612     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2613     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2614
2615     /* Win2k sends wparam set to
2616      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2617      * while Win9x doesn't bother to set child window id according to
2618      * CLIENTCREATESTRUCT.idFirstChild
2619      */
2620     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2621     { WM_SHOWWINDOW, sent|wparam, 1 },
2622     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2623
2624     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2625
2626     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2627     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2628     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2629
2630     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2631     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2632
2633     /* Win9x: message sequence terminates here. */
2634
2635     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2636     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2637     { HCBT_SETFOCUS, hook }, /* in MDI client */
2638     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2639     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2640     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2641     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2642     { HCBT_SETFOCUS, hook|optional },
2643     { WM_KILLFOCUS, sent }, /* in MDI client */
2644     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2645     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2646     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2647     { WM_SETFOCUS, sent|defwinproc },
2648
2649     { WM_MDIACTIVATE, sent|defwinproc },
2650
2651      /* in MDI child */
2652     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2653     { WM_NCCALCSIZE, sent|wparam, 1 },
2654     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2655     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2656
2657      /* in MDI frame */
2658     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2659     { WM_NCCALCSIZE, sent|wparam, 1 },
2660     { 0x0093, sent|defwinproc|optional },
2661     { 0x0093, sent|defwinproc|optional },
2662     { 0x0093, sent|defwinproc|optional },
2663     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2664     { WM_MOVE, sent|defwinproc },
2665     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2666
2667      /* in MDI client */
2668     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2669     { WM_NCCALCSIZE, sent|wparam, 1 },
2670     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2671     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2672
2673      /* in MDI child */
2674     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2675     { WM_NCCALCSIZE, sent|wparam, 1 },
2676     { 0x0093, sent|optional },
2677     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2678     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2679
2680     { 0x0093, sent|optional },
2681     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2682     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2683     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2684     { 0x0093, sent|defwinproc|optional },
2685     { 0x0093, sent|defwinproc|optional },
2686     { 0x0093, sent|defwinproc|optional },
2687     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2688     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2689
2690     { 0 }
2691 };
2692 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2693 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2694     { HCBT_CREATEWND, hook },
2695     { WM_GETMINMAXINFO, sent },
2696     { WM_NCCREATE, sent }, 
2697     { WM_NCCALCSIZE, sent|wparam, 0 },
2698     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2699     { WM_CREATE, sent },
2700     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2701     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2702     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2703     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2704     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2705     { WM_MOVE, sent },
2706     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2707     { WM_GETMINMAXINFO, sent },
2708     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2709     { WM_GETMINMAXINFO, sent|defwinproc },
2710     { WM_NCCALCSIZE, sent|wparam, 1 },
2711     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2712     { WM_MOVE, sent|defwinproc },
2713     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2714      /* in MDI frame */
2715     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2716     { WM_NCCALCSIZE, sent|wparam, 1 },
2717     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2718     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2719     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2720     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2721     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2722     /* Win2k sends wparam set to
2723      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2724      * while Win9x doesn't bother to set child window id according to
2725      * CLIENTCREATESTRUCT.idFirstChild
2726      */
2727     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2728     { 0 }
2729 };
2730 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2731 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2732     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2733     { HCBT_SYSCOMMAND, hook },
2734     { WM_CLOSE, sent|defwinproc },
2735     { WM_MDIDESTROY, sent }, /* in MDI client */
2736
2737     /* bring the 1st MDI child to top */
2738     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2739     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2740
2741     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2742
2743     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2744     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2745     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2746
2747     /* maximize the 1st MDI child */
2748     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2749     { WM_GETMINMAXINFO, sent|defwinproc },
2750     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2751     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2752     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2753     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2754     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2755
2756     /* restore the 2nd MDI child */
2757     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2758     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2759     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2760     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2761
2762     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2763
2764     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2765     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2766
2767     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2768
2769     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2770      /* in MDI frame */
2771     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2772     { WM_NCCALCSIZE, sent|wparam, 1 },
2773     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2774     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2775     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2776
2777     /* bring the 1st MDI child to top */
2778     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2779     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2780     { HCBT_SETFOCUS, hook },
2781     { WM_KILLFOCUS, sent|defwinproc },
2782     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2783     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2784     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2785     { WM_SETFOCUS, sent }, /* in MDI client */
2786     { HCBT_SETFOCUS, hook },
2787     { WM_KILLFOCUS, sent }, /* in MDI client */
2788     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2789     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2790     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2791     { WM_SETFOCUS, sent|defwinproc },
2792     { WM_MDIACTIVATE, sent|defwinproc },
2793     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2794
2795     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2796     { WM_SHOWWINDOW, sent|wparam, 1 },
2797     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2798     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2799     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2800     { WM_MDIREFRESHMENU, sent },
2801
2802     { HCBT_DESTROYWND, hook },
2803     /* Win2k sends wparam set to
2804      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2805      * while Win9x doesn't bother to set child window id according to
2806      * CLIENTCREATESTRUCT.idFirstChild
2807      */
2808     { 0x0090, sent|defwinproc|optional },
2809     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2810     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2811     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2812     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2813     { WM_ERASEBKGND, sent|parent|optional },
2814     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2815
2816     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2817     { WM_DESTROY, sent|defwinproc },
2818     { WM_NCDESTROY, sent|defwinproc },
2819     { 0 }
2820 };
2821 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2822 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2823     { WM_MDIDESTROY, sent }, /* in MDI client */
2824     { WM_SHOWWINDOW, sent|wparam, 0 },
2825     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2826     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2827     { WM_ERASEBKGND, sent|parent|optional },
2828     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2829
2830     { HCBT_SETFOCUS, hook },
2831     { WM_KILLFOCUS, sent },
2832     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2833     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2834     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2835     { WM_SETFOCUS, sent }, /* in MDI client */
2836     { HCBT_SETFOCUS, hook },
2837     { WM_KILLFOCUS, sent }, /* in MDI client */
2838     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2839     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2840     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2841     { WM_SETFOCUS, sent },
2842
2843      /* in MDI child */
2844     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2845     { WM_NCCALCSIZE, sent|wparam, 1 },
2846     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2847     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2848
2849      /* in MDI frame */
2850     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2851     { WM_NCCALCSIZE, sent|wparam, 1 },
2852     { 0x0093, sent|defwinproc|optional },
2853     { 0x0093, sent|defwinproc|optional },
2854     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2855     { WM_MOVE, sent|defwinproc },
2856     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2857
2858      /* in MDI client */
2859     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2860     { WM_NCCALCSIZE, sent|wparam, 1 },
2861     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2862     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2863
2864      /* in MDI child */
2865     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2866     { WM_NCCALCSIZE, sent|wparam, 1 },
2867     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2868     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
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_NOREDRAW|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|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2878     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2879     { 0x0093, sent|defwinproc|optional },
2880     { 0x0093, sent|defwinproc|optional },
2881     { 0x0093, sent|defwinproc|optional },
2882     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2883     { WM_MOVE, sent|defwinproc },
2884     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2885
2886      /* in MDI client */
2887     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2888     { WM_NCCALCSIZE, sent|wparam, 1 },
2889     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2890     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2891
2892      /* in MDI child */
2893     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2894     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2895     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2896     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2897     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2898     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2899
2900     { 0x0093, sent|defwinproc|optional },
2901     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2902     { 0x0093, sent|defwinproc|optional },
2903     { 0x0093, sent|defwinproc|optional },
2904     { 0x0093, sent|defwinproc|optional },
2905     { 0x0093, sent|optional },
2906
2907     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2908     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2909     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2910     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2911     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2912
2913      /* in MDI frame */
2914     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2915     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2916     { 0x0093, sent|defwinproc|optional },
2917     { 0x0093, sent|defwinproc|optional },
2918     { 0x0093, sent|defwinproc|optional },
2919     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2920     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2921     { 0x0093, sent|optional },
2922
2923     { WM_NCACTIVATE, sent|wparam, 0 },
2924     { WM_MDIACTIVATE, sent },
2925
2926     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2927     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2928     { WM_NCCALCSIZE, sent|wparam, 1 },
2929
2930     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2931
2932     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2933     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2934     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2935
2936      /* in MDI child */
2937     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2938     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2939     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2940     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2941
2942      /* in MDI frame */
2943     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2944     { WM_NCCALCSIZE, sent|wparam, 1 },
2945     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2946     { WM_MOVE, sent|defwinproc },
2947     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2948
2949      /* in MDI client */
2950     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2951     { WM_NCCALCSIZE, sent|wparam, 1 },
2952     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2953     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2954     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2955     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2956     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2957     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2958     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2959
2960     { HCBT_SETFOCUS, hook },
2961     { WM_KILLFOCUS, sent },
2962     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2963     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2964     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2965     { WM_SETFOCUS, sent }, /* in MDI client */
2966
2967     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2968
2969     { HCBT_DESTROYWND, hook },
2970     /* Win2k sends wparam set to
2971      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2972      * while Win9x doesn't bother to set child window id according to
2973      * CLIENTCREATESTRUCT.idFirstChild
2974      */
2975     { 0x0090, sent|optional },
2976     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2977
2978     { WM_SHOWWINDOW, sent|wparam, 0 },
2979     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2980     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2981     { WM_ERASEBKGND, sent|parent|optional },
2982     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2983
2984     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2985     { WM_DESTROY, sent },
2986     { WM_NCDESTROY, sent },
2987     { 0 }
2988 };
2989 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2990 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2991     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2992     { WM_GETMINMAXINFO, sent },
2993     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2994     { WM_NCCALCSIZE, sent|wparam, 1 },
2995     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2996     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2997
2998     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2999     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3000     { HCBT_SETFOCUS, hook|optional },
3001     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3002     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3003     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3004     { HCBT_SETFOCUS, hook|optional },
3005     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3006     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3007     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3008     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3009     { WM_SETFOCUS, sent|optional|defwinproc },
3010     { WM_MDIACTIVATE, sent|optional|defwinproc },
3011     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3012     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3013      /* in MDI frame */
3014     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3015     { WM_NCCALCSIZE, sent|wparam, 1 },
3016     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3017     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3018     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3019     { 0 }
3020 };
3021 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3022 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3023     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3024     { WM_GETMINMAXINFO, sent },
3025     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3026     { WM_GETMINMAXINFO, sent|defwinproc },
3027     { WM_NCCALCSIZE, sent|wparam, 1 },
3028     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3029     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3030
3031     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3032     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3033     { HCBT_SETFOCUS, hook|optional },
3034     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3035     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3036     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3037     { HCBT_SETFOCUS, hook|optional },
3038     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3039     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3040     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3041     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3042     { WM_SETFOCUS, sent|defwinproc|optional },
3043     { WM_MDIACTIVATE, sent|defwinproc|optional },
3044     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3045     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3046     { 0 }
3047 };
3048 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3049 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3050     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3051     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3052     { WM_GETMINMAXINFO, sent },
3053     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3054     { WM_GETMINMAXINFO, sent|defwinproc },
3055     { WM_NCCALCSIZE, sent|wparam, 1 },
3056     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3057     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3058     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3059     { WM_MOVE, sent|defwinproc },
3060     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3061
3062     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3063     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3064     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3065     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3066     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3067     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3068      /* in MDI frame */
3069     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3070     { WM_NCCALCSIZE, sent|wparam, 1 },
3071     { 0x0093, sent|defwinproc|optional },
3072     { 0x0094, sent|defwinproc|optional },
3073     { 0x0094, sent|defwinproc|optional },
3074     { 0x0094, sent|defwinproc|optional },
3075     { 0x0094, sent|defwinproc|optional },
3076     { 0x0093, sent|defwinproc|optional },
3077     { 0x0093, sent|defwinproc|optional },
3078     { 0x0091, sent|defwinproc|optional },
3079     { 0x0092, sent|defwinproc|optional },
3080     { 0x0092, sent|defwinproc|optional },
3081     { 0x0092, sent|defwinproc|optional },
3082     { 0x0092, sent|defwinproc|optional },
3083     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3084     { WM_MOVE, sent|defwinproc },
3085     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3086     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3087      /* in MDI client */
3088     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3089     { WM_NCCALCSIZE, sent|wparam, 1 },
3090     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3091     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3092      /* in MDI child */
3093     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3094     { WM_GETMINMAXINFO, sent|defwinproc },
3095     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3096     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3097     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3098     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3099     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3100     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3101     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3102     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3103      /* in MDI frame */
3104     { 0x0093, sent|optional },
3105     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3106     { 0x0093, sent|defwinproc|optional },
3107     { 0x0093, sent|defwinproc|optional },
3108     { 0x0093, sent|defwinproc|optional },
3109     { 0x0091, sent|defwinproc|optional },
3110     { 0x0092, sent|defwinproc|optional },
3111     { 0x0092, sent|defwinproc|optional },
3112     { 0x0092, sent|defwinproc|optional },
3113     { 0x0092, sent|defwinproc|optional },
3114     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3115     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3116     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3117     { 0 }
3118 };
3119 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3120 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3121     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3122     { WM_GETMINMAXINFO, sent },
3123     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3124     { WM_NCCALCSIZE, sent|wparam, 1 },
3125     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3126     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3127     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3128      /* in MDI frame */
3129     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3130     { WM_NCCALCSIZE, sent|wparam, 1 },
3131     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3132     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3133     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3134     { 0 }
3135 };
3136 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3137 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3138     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3139     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3140     { WM_NCCALCSIZE, sent|wparam, 1 },
3141     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3142     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3143     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3144      /* in MDI frame */
3145     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3146     { WM_NCCALCSIZE, sent|wparam, 1 },
3147     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3148     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3149     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3150     { 0 }
3151 };
3152 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3153 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3154     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3155     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3156     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3157     { WM_NCCALCSIZE, sent|wparam, 1 },
3158     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3159     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3160     { WM_MOVE, sent|defwinproc },
3161     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3162     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3163     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3164     { HCBT_SETFOCUS, hook },
3165     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3166     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3167     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3168     { WM_SETFOCUS, sent },
3169     { 0 }
3170 };
3171 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3172 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3173     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3174     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3175     { WM_NCCALCSIZE, sent|wparam, 1 },
3176     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
3177     { WM_MOVE, sent|defwinproc },
3178     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
3179     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3180     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3181     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3182     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3183     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3184     { 0 }
3185 };
3186 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3187 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3188     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3189     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3190     { WM_NCCALCSIZE, sent|wparam, 1 },
3191     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3192     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3193     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3194     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3195      /* in MDI frame */
3196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3197     { WM_NCCALCSIZE, sent|wparam, 1 },
3198     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3199     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3200     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3201     { 0 }
3202 };
3203
3204 static HWND mdi_client;
3205 static WNDPROC old_mdi_client_proc;
3206
3207 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3208 {
3209     struct recvd_message msg;
3210
3211     /* do not log painting messages */
3212     if (message != WM_PAINT &&
3213         message != WM_NCPAINT &&
3214         message != WM_SYNCPAINT &&
3215         message != WM_ERASEBKGND &&
3216         message != WM_NCHITTEST &&
3217         message != WM_GETTEXT &&
3218         message != WM_MDIGETACTIVE &&
3219         !ignore_message( message ))
3220     {
3221         msg.hwnd = hwnd;
3222         msg.message = message;
3223         msg.flags = sent|wparam|lparam;
3224         msg.wParam = wParam;
3225         msg.lParam = lParam;
3226         msg.descr = "mdi client";
3227         add_message(&msg);
3228     }
3229
3230     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3231 }
3232
3233 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3234 {
3235     static LONG defwndproc_counter = 0;
3236     LRESULT ret;
3237     struct recvd_message msg;
3238
3239     /* do not log painting messages */
3240     if (message != WM_PAINT &&
3241         message != WM_NCPAINT &&
3242         message != WM_SYNCPAINT &&
3243         message != WM_ERASEBKGND &&
3244         message != WM_NCHITTEST &&
3245         message != WM_GETTEXT &&
3246         !ignore_message( message ))
3247     {
3248         switch (message)
3249         {
3250             case WM_MDIACTIVATE:
3251             {
3252                 HWND active, client = GetParent(hwnd);
3253
3254                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3255
3256                 if (hwnd == (HWND)lParam) /* if we are being activated */
3257                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3258                 else
3259                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3260                 break;
3261             }
3262         }
3263
3264         msg.hwnd = hwnd;
3265         msg.message = message;
3266         msg.flags = sent|wparam|lparam;
3267         if (defwndproc_counter) msg.flags |= defwinproc;
3268         msg.wParam = wParam;
3269         msg.lParam = lParam;
3270         msg.descr = "mdi child";
3271         add_message(&msg);
3272     }
3273
3274     defwndproc_counter++;
3275     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3276     defwndproc_counter--;
3277
3278     return ret;
3279 }
3280
3281 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3282 {
3283     static LONG defwndproc_counter = 0;
3284     LRESULT ret;
3285     struct recvd_message msg;
3286
3287     /* do not log painting messages */
3288     if (message != WM_PAINT &&
3289         message != WM_NCPAINT &&
3290         message != WM_SYNCPAINT &&
3291         message != WM_ERASEBKGND &&
3292         message != WM_NCHITTEST &&
3293         message != WM_GETTEXT &&
3294         !ignore_message( message ))
3295     {
3296         msg.hwnd = hwnd;
3297         msg.message = message;
3298         msg.flags = sent|wparam|lparam;
3299         if (defwndproc_counter) msg.flags |= defwinproc;
3300         msg.wParam = wParam;
3301         msg.lParam = lParam;
3302         msg.descr = "mdi frame";
3303         add_message(&msg);
3304     }
3305
3306     defwndproc_counter++;
3307     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3308     defwndproc_counter--;
3309
3310     return ret;
3311 }
3312
3313 static BOOL mdi_RegisterWindowClasses(void)
3314 {
3315     WNDCLASSA cls;
3316
3317     cls.style = 0;
3318     cls.lpfnWndProc = mdi_frame_wnd_proc;
3319     cls.cbClsExtra = 0;
3320     cls.cbWndExtra = 0;
3321     cls.hInstance = GetModuleHandleA(0);
3322     cls.hIcon = 0;
3323     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3324     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3325     cls.lpszMenuName = NULL;
3326     cls.lpszClassName = "MDI_frame_class";
3327     if (!RegisterClassA(&cls)) return FALSE;
3328
3329     cls.lpfnWndProc = mdi_child_wnd_proc;
3330     cls.lpszClassName = "MDI_child_class";
3331     if (!RegisterClassA(&cls)) return FALSE;
3332
3333     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3334     old_mdi_client_proc = cls.lpfnWndProc;
3335     cls.hInstance = GetModuleHandleA(0);
3336     cls.lpfnWndProc = mdi_client_hook_proc;
3337     cls.lpszClassName = "MDI_client_class";
3338     if (!RegisterClassA(&cls)) assert(0);
3339
3340     return TRUE;
3341 }
3342
3343 static void test_mdi_messages(void)
3344 {
3345     MDICREATESTRUCTA mdi_cs;
3346     CLIENTCREATESTRUCT client_cs;
3347     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3348     BOOL zoomed;
3349     HMENU hMenu = CreateMenu();
3350
3351     assert(mdi_RegisterWindowClasses());
3352
3353     flush_sequence();
3354
3355     trace("creating MDI frame window\n");
3356     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3357                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3358                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3359                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3360                                 GetDesktopWindow(), hMenu,
3361                                 GetModuleHandleA(0), NULL);
3362     assert(mdi_frame);
3363     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3364
3365     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3366     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3367
3368     trace("creating MDI client window\n");
3369     client_cs.hWindowMenu = 0;
3370     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3371     mdi_client = CreateWindowExA(0, "MDI_client_class",
3372                                  NULL,
3373                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3374                                  0, 0, 0, 0,
3375                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3376     assert(mdi_client);
3377     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3378
3379     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3380     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3381
3382     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3383     ok(!active_child, "wrong active MDI child %p\n", active_child);
3384     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3385
3386     SetFocus(0);
3387     flush_sequence();
3388
3389     trace("creating invisible MDI child window\n");
3390     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3391                                 WS_CHILD,
3392                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3393                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3394     assert(mdi_child);
3395
3396     flush_sequence();
3397     ShowWindow(mdi_child, SW_SHOWNORMAL);
3398     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3399
3400     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3401     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3402
3403     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3404     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3405
3406     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3407     ok(!active_child, "wrong active MDI child %p\n", active_child);
3408     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3409
3410     ShowWindow(mdi_child, SW_HIDE);
3411     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3412     flush_sequence();
3413
3414     ShowWindow(mdi_child, SW_SHOW);
3415     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3416
3417     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3418     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3419
3420     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3421     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3422
3423     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3424     ok(!active_child, "wrong active MDI child %p\n", active_child);
3425     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3426
3427     DestroyWindow(mdi_child);
3428     flush_sequence();
3429
3430     trace("creating visible MDI child window\n");
3431     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3432                                 WS_CHILD | WS_VISIBLE,
3433                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3434                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3435     assert(mdi_child);
3436     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3437
3438     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3439     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3440
3441     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3442     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3443
3444     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3445     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3446     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3447     flush_sequence();
3448
3449     DestroyWindow(mdi_child);
3450     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3451
3452     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3453     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3454
3455     /* Win2k: MDI client still returns a just destroyed child as active
3456      * Win9x: MDI client returns 0
3457      */
3458     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3459     ok(active_child == mdi_child || /* win2k */
3460        !active_child, /* win9x */
3461        "wrong active MDI child %p\n", active_child);
3462     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3463
3464     flush_sequence();
3465
3466     trace("creating invisible MDI child window\n");
3467     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3468                                 WS_CHILD,
3469                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3470                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3471     assert(mdi_child2);
3472     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3473
3474     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3475     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3476
3477     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3478     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3479
3480     /* Win2k: MDI client still returns a just destroyed child as active
3481      * Win9x: MDI client returns mdi_child2
3482      */
3483     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3484     ok(active_child == mdi_child || /* win2k */
3485        active_child == mdi_child2, /* win9x */
3486        "wrong active MDI child %p\n", active_child);
3487     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3488     flush_sequence();
3489
3490     ShowWindow(mdi_child2, SW_MAXIMIZE);
3491     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3492
3493     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3494     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3495
3496     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3497     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3498     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3499     flush_sequence();
3500
3501     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3502     ok(GetFocus() == mdi_child2 || /* win2k */
3503        GetFocus() == 0, /* win9x */
3504        "wrong focus window %p\n", GetFocus());
3505
3506     SetFocus(0);
3507     flush_sequence();
3508
3509     ShowWindow(mdi_child2, SW_HIDE);
3510     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3511
3512     ShowWindow(mdi_child2, SW_RESTORE);
3513     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3514     flush_sequence();
3515
3516     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3517     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3518
3519     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3520     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3521     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3522     flush_sequence();
3523
3524     SetFocus(0);
3525     flush_sequence();
3526
3527     ShowWindow(mdi_child2, SW_HIDE);
3528     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3529
3530     ShowWindow(mdi_child2, SW_SHOW);
3531     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3532
3533     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3534     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3535
3536     ShowWindow(mdi_child2, SW_MAXIMIZE);
3537     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3538
3539     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3540     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3541
3542     ShowWindow(mdi_child2, SW_RESTORE);
3543     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3544
3545     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3546     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3547
3548     ShowWindow(mdi_child2, SW_MINIMIZE);
3549     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3550
3551     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3552     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3553
3554     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3555     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3556     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3557     flush_sequence();
3558
3559     ShowWindow(mdi_child2, SW_RESTORE);
3560     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3561
3562     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3563     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3564
3565     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3566     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3567     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3568     flush_sequence();
3569
3570     SetFocus(0);
3571     flush_sequence();
3572
3573     ShowWindow(mdi_child2, SW_HIDE);
3574     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3575
3576     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3577     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3578
3579     DestroyWindow(mdi_child2);
3580     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3581
3582     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3583     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3584
3585     /* test for maximized MDI children */
3586     trace("creating maximized visible MDI child window 1\n");
3587     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3588                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3589                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3590                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3591     assert(mdi_child);
3592     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3593     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3594
3595     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3596     ok(GetFocus() == mdi_child || /* win2k */
3597        GetFocus() == 0, /* win9x */
3598        "wrong focus window %p\n", GetFocus());
3599
3600     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3601     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3602     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3603     flush_sequence();
3604
3605     trace("creating maximized visible MDI child window 2\n");
3606     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3607                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3608                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3609                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3610     assert(mdi_child2);
3611     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3612     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3613     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3614
3615     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3616     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3617
3618     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3619     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3620     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3621     flush_sequence();
3622
3623     trace("destroying maximized visible MDI child window 2\n");
3624     DestroyWindow(mdi_child2);
3625     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3626
3627     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3628
3629     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3630     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3631
3632     /* Win2k: MDI client still returns a just destroyed child as active
3633      * Win9x: MDI client returns 0
3634      */
3635     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3636     ok(active_child == mdi_child2 || /* win2k */
3637        !active_child, /* win9x */
3638        "wrong active MDI child %p\n", active_child);
3639     flush_sequence();
3640
3641     ShowWindow(mdi_child, SW_MAXIMIZE);
3642     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3643     flush_sequence();
3644
3645     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3646     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3647
3648     trace("re-creating maximized visible MDI child window 2\n");
3649     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3650                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3651                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3652                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3653     assert(mdi_child2);
3654     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3655     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3656     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3657
3658     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3659     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
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_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3667     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3668     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3669
3670     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3671     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3672     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3673
3674     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3675     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3676     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3677     flush_sequence();
3678
3679     DestroyWindow(mdi_child);
3680     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3681
3682     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3683     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3684
3685     /* Win2k: MDI client still returns a just destroyed child as active
3686      * Win9x: MDI client returns 0
3687      */
3688     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3689     ok(active_child == mdi_child || /* win2k */
3690        !active_child, /* win9x */
3691        "wrong active MDI child %p\n", active_child);
3692     flush_sequence();
3693
3694     trace("creating maximized invisible MDI child window\n");
3695     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3696                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3697                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3698                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3699     assert(mdi_child2);
3700     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3701     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3702     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3703     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3704
3705     /* Win2k: MDI client still returns a just destroyed child as active
3706      * Win9x: MDI client returns 0
3707      */
3708     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3709     ok(active_child == mdi_child || /* win2k */
3710        !active_child || active_child == mdi_child2, /* win9x */
3711        "wrong active MDI child %p\n", active_child);
3712     flush_sequence();
3713
3714     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3715     ShowWindow(mdi_child2, SW_MAXIMIZE);
3716     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3717     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3718     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3719     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3720
3721     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3722     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3723     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3724     flush_sequence();
3725
3726     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3727     flush_sequence();
3728
3729     /* end of test for maximized MDI children */
3730     SetFocus(0);
3731     flush_sequence();
3732     trace("creating maximized visible MDI child window 1(Switch test)\n");
3733     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3734                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3735                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3736                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3737     assert(mdi_child);
3738     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3739     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3740
3741     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3742     ok(GetFocus() == mdi_child || /* win2k */
3743        GetFocus() == 0, /* win9x */
3744        "wrong focus window %p(Switch test)\n", GetFocus());
3745
3746     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3747     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3748     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3749     flush_sequence();
3750
3751     trace("creating maximized visible MDI child window 2(Switch test)\n");
3752     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3753                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3754                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3755                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3756     assert(mdi_child2);
3757     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3758
3759     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3760     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3761
3762     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3763     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3764
3765     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3766     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3767     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3768     flush_sequence();
3769
3770     trace("Switch child window.\n");
3771     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3772     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3773     trace("end of test for switch maximized MDI children\n");
3774     flush_sequence();
3775
3776     /* Prepare for switching test of not maximized MDI children  */
3777     ShowWindow( mdi_child, SW_NORMAL );
3778     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3779     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3780     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3781     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3782     flush_sequence();
3783
3784     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3785     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3786     trace("end of test for switch not maximized MDI children\n");
3787     flush_sequence();
3788
3789     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3790     flush_sequence();
3791
3792     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3793     flush_sequence();
3794
3795     SetFocus(0);
3796     flush_sequence();
3797     /* end of tests for switch maximized/not maximized MDI children */
3798
3799     mdi_cs.szClass = "MDI_child_Class";
3800     mdi_cs.szTitle = "MDI child";
3801     mdi_cs.hOwner = GetModuleHandleA(0);
3802     mdi_cs.x = 0;
3803     mdi_cs.y = 0;
3804     mdi_cs.cx = CW_USEDEFAULT;
3805     mdi_cs.cy = CW_USEDEFAULT;
3806     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3807     mdi_cs.lParam = 0;
3808     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3809     ok(mdi_child != 0, "MDI child creation failed\n");
3810     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3811
3812     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3813
3814     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3815     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3816
3817     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3818     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3819     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3820
3821     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3822     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3823     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3824     flush_sequence();
3825
3826     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3827     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3828
3829     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3830     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3831     ok(!active_child, "wrong active MDI child %p\n", active_child);
3832
3833     SetFocus(0);
3834     flush_sequence();
3835
3836     DestroyWindow(mdi_client);
3837     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3838
3839     /* test maximization of MDI child with invisible parent */
3840     client_cs.hWindowMenu = 0;
3841     mdi_client = CreateWindow("MDI_client_class",
3842                                  NULL,
3843                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3844                                  0, 0, 660, 430,
3845                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3846     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3847
3848     ShowWindow(mdi_client, SW_HIDE);
3849     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3850
3851     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3852                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3853                                 0, 0, 650, 440,
3854                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3855     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3856
3857     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3858     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3859     zoomed = IsZoomed(mdi_child);
3860     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3861     
3862     ShowWindow(mdi_client, SW_SHOW);
3863     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3864
3865     DestroyWindow(mdi_child);
3866     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3867
3868     /* end of test for maximization of MDI child with invisible parent */
3869
3870     DestroyWindow(mdi_client);
3871     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3872
3873     DestroyWindow(mdi_frame);
3874     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3875 }
3876 /************************* End of MDI test **********************************/
3877
3878 static void test_WM_SETREDRAW(HWND hwnd)
3879 {
3880     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3881
3882     flush_events();
3883     flush_sequence();
3884
3885     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3886     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3887
3888     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3889     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3890
3891     flush_sequence();
3892     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3893     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3894
3895     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3896     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3897
3898     /* restore original WS_VISIBLE state */
3899     SetWindowLongA(hwnd, GWL_STYLE, style);
3900
3901     flush_events();
3902     flush_sequence();
3903 }
3904
3905 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3906 {
3907     struct recvd_message msg;
3908
3909     if (ignore_message( message )) return 0;
3910
3911     switch (message)
3912     {
3913         /* ignore */
3914         case WM_MOUSEMOVE:
3915         case WM_NCMOUSEMOVE:
3916         case WM_NCMOUSELEAVE:
3917         case WM_SETCURSOR:
3918             return 0;
3919         case WM_NCHITTEST:
3920             return HTCLIENT;
3921     }
3922
3923     msg.hwnd = hwnd;
3924     msg.message = message;
3925     msg.flags = sent|wparam|lparam;
3926     msg.wParam = wParam;
3927     msg.lParam = lParam;
3928     msg.descr = "dialog";
3929     add_message(&msg);
3930
3931     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3932     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3933     return 0;
3934 }
3935
3936 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3937 {
3938     DWORD style, exstyle;
3939     INT xmin, xmax;
3940     BOOL ret;
3941
3942     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3943     style = GetWindowLongA(hwnd, GWL_STYLE);
3944     /* do not be confused by WS_DLGFRAME set */
3945     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3946
3947     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3948     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3949
3950     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3951     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3952     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3953         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3954     else
3955         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3956
3957     style = GetWindowLongA(hwnd, GWL_STYLE);
3958     if (set) ok(style & set, "style %08x should be set\n", set);
3959     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3960
3961     /* a subsequent call should do nothing */
3962     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3963     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3964     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3965
3966     xmin = 0xdeadbeef;
3967     xmax = 0xdeadbeef;
3968     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3969     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3970     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3971     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3972     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3973     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3974 }
3975
3976 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3977 {
3978     DWORD style, exstyle;
3979     SCROLLINFO si;
3980     BOOL ret;
3981
3982     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3983     style = GetWindowLongA(hwnd, GWL_STYLE);
3984     /* do not be confused by WS_DLGFRAME set */
3985     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3986
3987     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3988     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3989
3990     si.cbSize = sizeof(si);
3991     si.fMask = SIF_RANGE;
3992     si.nMin = min;
3993     si.nMax = max;
3994     SetScrollInfo(hwnd, ctl, &si, TRUE);
3995     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3996         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3997     else
3998         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3999
4000     style = GetWindowLongA(hwnd, GWL_STYLE);
4001     if (set) ok(style & set, "style %08x should be set\n", set);
4002     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4003
4004     /* a subsequent call should do nothing */
4005     SetScrollInfo(hwnd, ctl, &si, TRUE);
4006     if (style & WS_HSCROLL)
4007         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4008     else if (style & WS_VSCROLL)
4009         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4010     else
4011         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4012
4013     si.fMask = SIF_PAGE;
4014     si.nPage = 5;
4015     SetScrollInfo(hwnd, ctl, &si, FALSE);
4016     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4017
4018     si.fMask = SIF_POS;
4019     si.nPos = max - 1;
4020     SetScrollInfo(hwnd, ctl, &si, FALSE);
4021     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4022
4023     si.fMask = SIF_RANGE;
4024     si.nMin = 0xdeadbeef;
4025     si.nMax = 0xdeadbeef;
4026     ret = GetScrollInfo(hwnd, ctl, &si);
4027     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4028     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4029     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4030     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4031 }
4032
4033 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4034 static void test_scroll_messages(HWND hwnd)
4035 {
4036     SCROLLINFO si;
4037     INT min, max;
4038     BOOL ret;
4039
4040     flush_events();
4041     flush_sequence();
4042
4043     min = 0xdeadbeef;
4044     max = 0xdeadbeef;
4045     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4046     ok( ret, "GetScrollRange error %d\n", GetLastError());
4047     if (sequence->message != WmGetScrollRangeSeq[0].message)
4048         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4049     /* values of min and max are undefined */
4050     flush_sequence();
4051
4052     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4053     ok( ret, "SetScrollRange error %d\n", GetLastError());
4054     if (sequence->message != WmSetScrollRangeSeq[0].message)
4055         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4056     flush_sequence();
4057
4058     min = 0xdeadbeef;
4059     max = 0xdeadbeef;
4060     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4061     ok( ret, "GetScrollRange error %d\n", GetLastError());
4062     if (sequence->message != WmGetScrollRangeSeq[0].message)
4063         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4064     /* values of min and max are undefined */
4065     flush_sequence();
4066
4067     si.cbSize = sizeof(si);
4068     si.fMask = SIF_RANGE;
4069     si.nMin = 20;
4070     si.nMax = 160;
4071     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4072     if (sequence->message != WmSetScrollRangeSeq[0].message)
4073         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4074     flush_sequence();
4075
4076     si.fMask = SIF_PAGE;
4077     si.nPage = 10;
4078     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4079     if (sequence->message != WmSetScrollRangeSeq[0].message)
4080         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4081     flush_sequence();
4082
4083     si.fMask = SIF_POS;
4084     si.nPos = 20;
4085     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4086     if (sequence->message != WmSetScrollRangeSeq[0].message)
4087         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4088     flush_sequence();
4089
4090     si.fMask = SIF_RANGE;
4091     si.nMin = 0xdeadbeef;
4092     si.nMax = 0xdeadbeef;
4093     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4094     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4095     if (sequence->message != WmGetScrollInfoSeq[0].message)
4096         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4097     /* values of min and max are undefined */
4098     flush_sequence();
4099
4100     /* set WS_HSCROLL */
4101     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4102     /* clear WS_HSCROLL */
4103     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4104
4105     /* set WS_HSCROLL */
4106     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4107     /* clear WS_HSCROLL */
4108     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4109
4110     /* set WS_VSCROLL */
4111     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4112     /* clear WS_VSCROLL */
4113     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4114
4115     /* set WS_VSCROLL */
4116     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4117     /* clear WS_VSCROLL */
4118     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4119 }
4120
4121 static void test_showwindow(void)
4122 {
4123     HWND hwnd, hchild;
4124     RECT rc;
4125
4126     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4127                            100, 100, 200, 200, 0, 0, 0, NULL);
4128     ok (hwnd != 0, "Failed to create overlapped window\n");
4129     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4130                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4131     ok (hchild != 0, "Failed to create child\n");
4132     flush_sequence();
4133
4134     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4135     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4136     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4137     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4138
4139     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4140     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4141     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4142     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4143     /* back to invisible */
4144     ShowWindow(hchild, SW_HIDE);
4145     ShowWindow(hwnd, SW_HIDE);
4146     flush_sequence();
4147     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4148     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4149     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4150     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4151     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4152     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4153     flush_sequence();
4154     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4155     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4156     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4157     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4158     ShowWindow( hwnd, SW_SHOW);
4159     flush_sequence();
4160     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4161     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4162     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4163
4164     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4165     ShowWindow( hchild, SW_HIDE);
4166     flush_sequence();
4167     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4168     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4169     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4170
4171     SetCapture(hchild);
4172     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4173     DestroyWindow(hchild);
4174     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4175
4176     DestroyWindow(hwnd);
4177     flush_sequence();
4178
4179     /* Popup windows */
4180     /* Test 1:
4181      * 1. Create invisible maximized popup window.
4182      * 2. Move and resize it.
4183      * 3. Show it maximized.
4184      */
4185     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4186     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4187                            100, 100, 200, 200, 0, 0, 0, NULL);
4188     ok (hwnd != 0, "Failed to create popup window\n");
4189     ok(IsZoomed(hwnd), "window should be maximized\n");
4190     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4191
4192     GetWindowRect(hwnd, &rc);
4193     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4194         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4195         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4196         rc.left, rc.top, rc.right, rc.bottom);
4197     /* Reset window's size & position */
4198     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4199     ok(IsZoomed(hwnd), "window should be maximized\n");
4200     flush_sequence();
4201
4202     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4203     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4204     ok(IsZoomed(hwnd), "window should be maximized\n");
4205     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4206
4207     GetWindowRect(hwnd, &rc);
4208     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4209         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4210         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4211         rc.left, rc.top, rc.right, rc.bottom);
4212     DestroyWindow(hwnd);
4213     flush_sequence();
4214
4215     /* Test 2:
4216      * 1. Create invisible maximized popup window.
4217      * 2. Show it maximized.
4218      */
4219     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4220     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4221                            100, 100, 200, 200, 0, 0, 0, NULL);
4222     ok (hwnd != 0, "Failed to create popup window\n");
4223     ok(IsZoomed(hwnd), "window should be maximized\n");
4224     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4225
4226     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4227     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4228     ok(IsZoomed(hwnd), "window should be maximized\n");
4229     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4230     DestroyWindow(hwnd);
4231     flush_sequence();
4232
4233     /* Test 3:
4234      * 1. Create visible maximized popup window.
4235      */
4236     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4237     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4238                            100, 100, 200, 200, 0, 0, 0, NULL);
4239     ok (hwnd != 0, "Failed to create popup window\n");
4240     ok(IsZoomed(hwnd), "window should be maximized\n");
4241     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4242     DestroyWindow(hwnd);
4243     flush_sequence();
4244
4245     /* Test 4:
4246      * 1. Create visible popup window.
4247      * 2. Maximize it.
4248      */
4249     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4250     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4251                            100, 100, 200, 200, 0, 0, 0, NULL);
4252     ok (hwnd != 0, "Failed to create popup window\n");
4253     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4254     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4255
4256     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4257     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4258     ok(IsZoomed(hwnd), "window should be maximized\n");
4259     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4260     DestroyWindow(hwnd);
4261     flush_sequence();
4262 }
4263
4264 static void test_sys_menu(void)
4265 {
4266     HWND hwnd;
4267     HMENU hmenu;
4268     UINT state;
4269
4270     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4271                            100, 100, 200, 200, 0, 0, 0, NULL);
4272     ok (hwnd != 0, "Failed to create overlapped window\n");
4273
4274     flush_sequence();
4275
4276     /* test existing window without CS_NOCLOSE style */
4277     hmenu = GetSystemMenu(hwnd, FALSE);
4278     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4279
4280     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4281     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4282     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4283
4284     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4285     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4286
4287     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4288     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4289     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4290
4291     EnableMenuItem(hmenu, SC_CLOSE, 0);
4292     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4293
4294     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4295     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4296     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4297
4298     /* test whether removing WS_SYSMENU destroys a system menu */
4299     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4300     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4301     flush_sequence();
4302     hmenu = GetSystemMenu(hwnd, FALSE);
4303     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4304
4305     DestroyWindow(hwnd);
4306
4307     /* test new window with CS_NOCLOSE style */
4308     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4309                            100, 100, 200, 200, 0, 0, 0, NULL);
4310     ok (hwnd != 0, "Failed to create overlapped window\n");
4311
4312     hmenu = GetSystemMenu(hwnd, FALSE);
4313     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4314
4315     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4316     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4317
4318     DestroyWindow(hwnd);
4319
4320     /* test new window without WS_SYSMENU style */
4321     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4322                            100, 100, 200, 200, 0, 0, 0, NULL);
4323     ok(hwnd != 0, "Failed to create overlapped window\n");
4324
4325     hmenu = GetSystemMenu(hwnd, FALSE);
4326     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4327
4328     DestroyWindow(hwnd);
4329 }
4330
4331 /* For shown WS_OVERLAPPEDWINDOW */
4332 static const struct message WmSetIcon_1[] = {
4333     { WM_SETICON, sent },
4334     { 0x00AE, sent|defwinproc|optional }, /* XP */
4335     { WM_GETTEXT, sent|defwinproc|optional },
4336     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4337     { 0 }
4338 };
4339
4340 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4341 static const struct message WmSetIcon_2[] = {
4342     { WM_SETICON, sent },
4343     { 0 }
4344 };
4345
4346 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4347 static const struct message WmInitEndSession[] = {
4348     { 0x003B, sent },
4349     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4350     { 0 }
4351 };
4352
4353 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4354 static const struct message WmInitEndSession_2[] = {
4355     { 0x003B, sent },
4356     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4357     { 0 }
4358 };
4359
4360 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4361 static const struct message WmInitEndSession_3[] = {
4362     { 0x003B, sent },
4363     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4364     { 0 }
4365 };
4366
4367 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4368 static const struct message WmInitEndSession_4[] = {
4369     { 0x003B, sent },
4370     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4371     { 0 }
4372 };
4373
4374 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4375 static const struct message WmInitEndSession_5[] = {
4376     { 0x003B, sent },
4377     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4378     { 0 }
4379 };
4380
4381 static const struct message WmOptionalPaint[] = {
4382     { WM_PAINT, sent|optional },
4383     { WM_NCPAINT, sent|beginpaint|optional },
4384     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4385     { WM_ERASEBKGND, sent|beginpaint|optional },
4386     { 0 }
4387 };
4388
4389 static const struct message WmZOrder[] = {
4390     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4391     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4392     { HCBT_ACTIVATE, hook },
4393     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4394     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4395     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4396     { WM_GETTEXT, sent|optional },
4397     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4398     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4399     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4400     { WM_GETTEXT, sent|defwinproc|optional },
4401     { WM_GETTEXT, sent|defwinproc|optional },
4402     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4403     { HCBT_SETFOCUS, hook },
4404     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4405     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4406     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4407     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4408     { WM_GETTEXT, sent|optional },
4409     { WM_NCCALCSIZE, sent|optional },
4410     { 0 }
4411 };
4412
4413 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4414 {
4415     DWORD ret;
4416     MSG msg;
4417
4418     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4419     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4420
4421     PostMessageA(hwnd, WM_USER, 0, 0);
4422
4423     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4424     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4425
4426     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4427     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4428
4429     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4430     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4431
4432     PostMessageA(hwnd, WM_USER, 0, 0);
4433
4434     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4435     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4436
4437     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4438     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4439
4440     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4441     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4442     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4443
4444     PostMessageA(hwnd, WM_USER, 0, 0);
4445
4446     /* new incoming message causes it to become signaled again */
4447     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4448     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4449
4450     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4451     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4452     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4453     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4454 }
4455
4456 /* test if we receive the right sequence of messages */
4457 static void test_messages(void)
4458 {
4459     HWND hwnd, hparent, hchild;
4460     HWND hchild2, hbutton;
4461     HMENU hmenu;
4462     MSG msg;
4463     LRESULT res;
4464
4465     flush_sequence();
4466
4467     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4468                            100, 100, 200, 200, 0, 0, 0, NULL);
4469     ok (hwnd != 0, "Failed to create overlapped window\n");
4470     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4471
4472     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4473     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4474     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4475
4476     /* test WM_SETREDRAW on a not visible top level window */
4477     test_WM_SETREDRAW(hwnd);
4478
4479     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4480     flush_events();
4481     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4482     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4483
4484     ok(GetActiveWindow() == hwnd, "window should be active\n");
4485     ok(GetFocus() == hwnd, "window should have input focus\n");
4486     ShowWindow(hwnd, SW_HIDE);
4487     flush_events();
4488     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4489
4490     ShowWindow(hwnd, SW_SHOW);
4491     flush_events();
4492     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4493
4494     ShowWindow(hwnd, SW_HIDE);
4495     flush_events();
4496     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4497
4498     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4499     flush_events();
4500     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4501     flush_sequence();
4502
4503     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4504     {
4505         ShowWindow(hwnd, SW_RESTORE);
4506         flush_events();
4507         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4508         flush_sequence();
4509     }
4510
4511     ShowWindow(hwnd, SW_MINIMIZE);
4512     flush_events();
4513     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4514     flush_sequence();
4515
4516     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4517     {
4518         ShowWindow(hwnd, SW_RESTORE);
4519         flush_events();
4520         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4521         flush_sequence();
4522     }
4523
4524     ShowWindow(hwnd, SW_SHOW);
4525     flush_events();
4526     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4527
4528     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4529     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4530     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4531     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4532
4533     /* test WM_SETREDRAW on a visible top level window */
4534     ShowWindow(hwnd, SW_SHOW);
4535     flush_events();
4536     test_WM_SETREDRAW(hwnd);
4537
4538     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4539     test_scroll_messages(hwnd);
4540
4541     /* test resizing and moving */
4542     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4543     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4544     flush_events();
4545     flush_sequence();
4546     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4547     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4548     flush_events();
4549     flush_sequence();
4550     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4551     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4552     flush_events();
4553     flush_sequence();
4554
4555     /* popups don't get WM_GETMINMAXINFO */
4556     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4557     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4558     flush_sequence();
4559     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4560     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4561
4562     DestroyWindow(hwnd);
4563     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4564
4565     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4566                               100, 100, 200, 200, 0, 0, 0, NULL);
4567     ok (hparent != 0, "Failed to create parent window\n");
4568     flush_sequence();
4569
4570     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4571                              0, 0, 10, 10, hparent, 0, 0, NULL);
4572     ok (hchild != 0, "Failed to create child window\n");
4573     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4574     DestroyWindow(hchild);
4575     flush_sequence();
4576
4577     /* visible child window with a caption */
4578     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4579                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4580                              0, 0, 10, 10, hparent, 0, 0, NULL);
4581     ok (hchild != 0, "Failed to create child window\n");
4582     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4583
4584     trace("testing scroll APIs on a visible child window %p\n", hchild);
4585     test_scroll_messages(hchild);
4586
4587     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4588     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4589
4590     DestroyWindow(hchild);
4591     flush_sequence();
4592
4593     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4594                              0, 0, 10, 10, hparent, 0, 0, NULL);
4595     ok (hchild != 0, "Failed to create child window\n");
4596     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4597     
4598     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4599                                100, 100, 50, 50, hparent, 0, 0, NULL);
4600     ok (hchild2 != 0, "Failed to create child2 window\n");
4601     flush_sequence();
4602
4603     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4604                               0, 100, 50, 50, hchild, 0, 0, NULL);
4605     ok (hbutton != 0, "Failed to create button window\n");
4606
4607     /* test WM_SETREDRAW on a not visible child window */
4608     test_WM_SETREDRAW(hchild);
4609
4610     ShowWindow(hchild, SW_SHOW);
4611     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4612
4613     /* check parent messages too */
4614     log_all_parent_messages++;
4615     ShowWindow(hchild, SW_HIDE);
4616     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4617     log_all_parent_messages--;
4618
4619     ShowWindow(hchild, SW_SHOW);
4620     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4621
4622     ShowWindow(hchild, SW_HIDE);
4623     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4624
4625     ShowWindow(hchild, SW_SHOW);
4626     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4627
4628     /* test WM_SETREDRAW on a visible child window */
4629     test_WM_SETREDRAW(hchild);
4630
4631     log_all_parent_messages++;
4632     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4633     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4634     log_all_parent_messages--;
4635
4636     ShowWindow(hchild, SW_HIDE);
4637     flush_sequence();
4638     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4639     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4640
4641     ShowWindow(hchild, SW_HIDE);
4642     flush_sequence();
4643     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4644     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4645
4646     /* DestroyWindow sequence below expects that a child has focus */
4647     SetFocus(hchild);
4648     flush_sequence();
4649
4650     DestroyWindow(hchild);
4651     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4652     DestroyWindow(hchild2);
4653     DestroyWindow(hbutton);
4654
4655     flush_sequence();
4656     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4657                              0, 0, 100, 100, hparent, 0, 0, NULL);
4658     ok (hchild != 0, "Failed to create child popup window\n");
4659     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4660     DestroyWindow(hchild);
4661
4662     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4663     flush_sequence();
4664     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4665                              0, 0, 100, 100, hparent, 0, 0, NULL);
4666     ok (hchild != 0, "Failed to create popup window\n");
4667     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4668     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4669     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4670     flush_sequence();
4671     ShowWindow(hchild, SW_SHOW);
4672     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4673     flush_sequence();
4674     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4675     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4676     flush_sequence();
4677     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4678     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4679     DestroyWindow(hchild);
4680
4681     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4682      * changes nothing in message sequences.
4683      */
4684     flush_sequence();
4685     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4686                              0, 0, 100, 100, hparent, 0, 0, NULL);
4687     ok (hchild != 0, "Failed to create popup window\n");
4688     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4689     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4690     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4691     flush_sequence();
4692     ShowWindow(hchild, SW_SHOW);
4693     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4694     flush_sequence();
4695     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4696     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4697     DestroyWindow(hchild);
4698
4699     flush_sequence();
4700     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4701                            0, 0, 100, 100, hparent, 0, 0, NULL);
4702     ok(hwnd != 0, "Failed to create custom dialog window\n");
4703     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4704
4705     /*
4706     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4707     test_scroll_messages(hwnd);
4708     */
4709
4710     flush_sequence();
4711
4712     test_def_id = 1;
4713     SendMessage(hwnd, WM_NULL, 0, 0);
4714
4715     flush_sequence();
4716     after_end_dialog = 1;
4717     EndDialog( hwnd, 0 );
4718     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4719
4720     DestroyWindow(hwnd);
4721     after_end_dialog = 0;
4722     test_def_id = 0;
4723
4724     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4725                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4726     ok(hwnd != 0, "Failed to create custom dialog window\n");
4727     flush_sequence();
4728     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4729     ShowWindow(hwnd, SW_SHOW);
4730     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4731     DestroyWindow(hwnd);
4732
4733     flush_sequence();
4734     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4735     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4736
4737     DestroyWindow(hparent);
4738     flush_sequence();
4739
4740     /* Message sequence for SetMenu */
4741     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4742     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4743
4744     hmenu = CreateMenu();
4745     ok (hmenu != 0, "Failed to create menu\n");
4746     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4747     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4748                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4749     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4750     ok (SetMenu(hwnd, 0), "SetMenu\n");
4751     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4752     ok (SetMenu(hwnd, 0), "SetMenu\n");
4753     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4754     ShowWindow(hwnd, SW_SHOW);
4755     UpdateWindow( hwnd );
4756     flush_events();
4757     flush_sequence();
4758     ok (SetMenu(hwnd, 0), "SetMenu\n");
4759     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4760     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4761     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4762
4763     UpdateWindow( hwnd );
4764     flush_events();
4765     flush_sequence();
4766     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4767     flush_events();
4768     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4769
4770     DestroyWindow(hwnd);
4771     flush_sequence();
4772
4773     /* Message sequence for EnableWindow */
4774     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4775                               100, 100, 200, 200, 0, 0, 0, NULL);
4776     ok (hparent != 0, "Failed to create parent window\n");
4777     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4778                              0, 0, 10, 10, hparent, 0, 0, NULL);
4779     ok (hchild != 0, "Failed to create child window\n");
4780
4781     SetFocus(hchild);
4782     flush_events();
4783     flush_sequence();
4784
4785     EnableWindow(hparent, FALSE);
4786     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4787
4788     EnableWindow(hparent, TRUE);
4789     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4790
4791     flush_events();
4792     flush_sequence();
4793
4794     test_MsgWaitForMultipleObjects(hparent);
4795
4796     /* the following test causes an exception in user.exe under win9x */
4797     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4798     {
4799         DestroyWindow(hparent);
4800         flush_sequence();
4801         return;
4802     }
4803     PostMessageW( hparent, WM_USER+1, 0, 0 );
4804     /* PeekMessage(NULL) fails, but still removes the message */
4805     SetLastError(0xdeadbeef);
4806     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4807     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4808         GetLastError() == 0xdeadbeef, /* NT4 */
4809         "last error is %d\n", GetLastError() );
4810     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4811     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4812
4813     DestroyWindow(hchild);
4814     DestroyWindow(hparent);
4815     flush_sequence();
4816
4817     /* Message sequences for WM_SETICON */
4818     trace("testing WM_SETICON\n");
4819     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4820                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4821                            NULL, NULL, 0);
4822     ShowWindow(hwnd, SW_SHOW);
4823     UpdateWindow(hwnd);
4824     flush_events();
4825     flush_sequence();
4826     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4827     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4828
4829     ShowWindow(hwnd, SW_HIDE);
4830     flush_events();
4831     flush_sequence();
4832     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4833     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4834     DestroyWindow(hwnd);
4835     flush_sequence();
4836
4837     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4838                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4839                            NULL, NULL, 0);
4840     ShowWindow(hwnd, SW_SHOW);
4841     UpdateWindow(hwnd);
4842     flush_events();
4843     flush_sequence();
4844     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4845     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4846
4847     ShowWindow(hwnd, SW_HIDE);
4848     flush_events();
4849     flush_sequence();
4850     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4851     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4852
4853     flush_sequence();
4854     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4855     if (!res)
4856     {
4857         todo_wine win_skip( "Message 0x3b not supported\n" );
4858         goto done;
4859     }
4860     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4861     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4862     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4863     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4864     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4865     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4866     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4867     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4868
4869     flush_sequence();
4870     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4871     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4872     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4873     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4874     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4875     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4876
4877     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4878     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4879     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4880
4881     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4882     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4883     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4884
4885 done:
4886     DestroyWindow(hwnd);
4887     flush_sequence();
4888 }
4889
4890 static void test_setwindowpos(void)
4891 {
4892     HWND hwnd;
4893     RECT rc;
4894     LRESULT res;
4895     const INT winX = 100;
4896     const INT winY = 100;
4897     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4898
4899     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4900                            0, 0, winX, winY, 0,
4901                            NULL, NULL, 0);
4902
4903     GetWindowRect(hwnd, &rc);
4904     expect(sysX, rc.right);
4905     expect(winY, rc.bottom);
4906
4907     flush_events();
4908     flush_sequence();
4909     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4910     ok_sequence(WmZOrder, "Z-Order", TRUE);
4911     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4912
4913     GetWindowRect(hwnd, &rc);
4914     expect(sysX, rc.right);
4915     expect(winY, rc.bottom);
4916     DestroyWindow(hwnd);
4917 }
4918
4919 static void invisible_parent_tests(void)
4920 {
4921     HWND hparent, hchild;
4922
4923     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4924                               100, 100, 200, 200, 0, 0, 0, NULL);
4925     ok (hparent != 0, "Failed to create parent window\n");
4926     flush_sequence();
4927
4928     /* test showing child with hidden parent */
4929
4930     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4931                              0, 0, 10, 10, hparent, 0, 0, NULL);
4932     ok (hchild != 0, "Failed to create child window\n");
4933     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4934
4935     ShowWindow( hchild, SW_MINIMIZE );
4936     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4937     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4938     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4939
4940     /* repeat */
4941     flush_events();
4942     flush_sequence();
4943     ShowWindow( hchild, SW_MINIMIZE );
4944     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4945
4946     DestroyWindow(hchild);
4947     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4948                              0, 0, 10, 10, hparent, 0, 0, NULL);
4949     flush_sequence();
4950
4951     ShowWindow( hchild, SW_MAXIMIZE );
4952     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4953     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4954     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4955
4956     /* repeat */
4957     flush_events();
4958     flush_sequence();
4959     ShowWindow( hchild, SW_MAXIMIZE );
4960     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4961
4962     DestroyWindow(hchild);
4963     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4964                              0, 0, 10, 10, hparent, 0, 0, NULL);
4965     flush_sequence();
4966
4967     ShowWindow( hchild, SW_RESTORE );
4968     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4969     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4970     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4971
4972     DestroyWindow(hchild);
4973     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4974                              0, 0, 10, 10, hparent, 0, 0, NULL);
4975     flush_sequence();
4976
4977     ShowWindow( hchild, SW_SHOWMINIMIZED );
4978     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4979     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4980     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4981
4982     /* repeat */
4983     flush_events();
4984     flush_sequence();
4985     ShowWindow( hchild, SW_SHOWMINIMIZED );
4986     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4987
4988     DestroyWindow(hchild);
4989     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4990                              0, 0, 10, 10, hparent, 0, 0, NULL);
4991     flush_sequence();
4992
4993     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4994     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4995     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4996     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4997     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4998
4999     DestroyWindow(hchild);
5000     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5001                              0, 0, 10, 10, hparent, 0, 0, NULL);
5002     flush_sequence();
5003
5004     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5005     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5006     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5007     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5008
5009     /* repeat */
5010     flush_events();
5011     flush_sequence();
5012     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5013     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5014
5015     DestroyWindow(hchild);
5016     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5017                              0, 0, 10, 10, hparent, 0, 0, NULL);
5018     flush_sequence();
5019
5020     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5021     ShowWindow( hchild, SW_FORCEMINIMIZE );
5022     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5023 todo_wine {
5024     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5025 }
5026     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5027
5028     DestroyWindow(hchild);
5029     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5030                              0, 0, 10, 10, hparent, 0, 0, NULL);
5031     flush_sequence();
5032
5033     ShowWindow( hchild, SW_SHOWNA );
5034     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5035     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5036     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5037
5038     /* repeat */
5039     flush_events();
5040     flush_sequence();
5041     ShowWindow( hchild, SW_SHOWNA );
5042     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5043
5044     DestroyWindow(hchild);
5045     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5046                              0, 0, 10, 10, hparent, 0, 0, NULL);
5047     flush_sequence();
5048
5049     ShowWindow( hchild, SW_SHOW );
5050     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5051     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5052     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5053
5054     /* repeat */
5055     flush_events();
5056     flush_sequence();
5057     ShowWindow( hchild, SW_SHOW );
5058     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5059
5060     ShowWindow( hchild, SW_HIDE );
5061     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5062     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5063     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5064
5065     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5066     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5067     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5068     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5069
5070     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5071     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5072     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5073     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5074
5075     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5076     flush_sequence();
5077     DestroyWindow(hchild);
5078     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5079
5080     DestroyWindow(hparent);
5081     flush_sequence();
5082 }
5083
5084 /****************** button message test *************************/
5085 static const struct message WmSetFocusButtonSeq[] =
5086 {
5087     { HCBT_SETFOCUS, hook },
5088     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5089     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5090     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5091     { WM_SETFOCUS, sent|wparam, 0 },
5092     { WM_CTLCOLORBTN, sent|defwinproc },
5093     { 0 }
5094 };
5095 static const struct message WmKillFocusButtonSeq[] =
5096 {
5097     { HCBT_SETFOCUS, hook },
5098     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5099     { WM_KILLFOCUS, sent|wparam, 0 },
5100     { WM_CTLCOLORBTN, sent|defwinproc },
5101     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5102     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5103     { 0 }
5104 };
5105 static const struct message WmSetFocusStaticSeq[] =
5106 {
5107     { HCBT_SETFOCUS, hook },
5108     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5109     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5110     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5111     { WM_SETFOCUS, sent|wparam, 0 },
5112     { WM_CTLCOLORSTATIC, sent|defwinproc },
5113     { 0 }
5114 };
5115 static const struct message WmKillFocusStaticSeq[] =
5116 {
5117     { HCBT_SETFOCUS, hook },
5118     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5119     { WM_KILLFOCUS, sent|wparam, 0 },
5120     { WM_CTLCOLORSTATIC, sent|defwinproc },
5121     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5122     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5123     { 0 }
5124 };
5125 static const struct message WmLButtonDownSeq[] =
5126 {
5127     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5128     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5129     { HCBT_SETFOCUS, hook },
5130     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5131     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5132     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5133     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5134     { WM_CTLCOLORBTN, sent|defwinproc },
5135     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5136     { WM_CTLCOLORBTN, sent|defwinproc },
5137     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5138     { 0 }
5139 };
5140 static const struct message WmLButtonUpSeq[] =
5141 {
5142     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5143     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5144     { WM_CTLCOLORBTN, sent|defwinproc },
5145     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5146     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5147     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5148     { 0 }
5149 };
5150 static const struct message WmSetFontButtonSeq[] =
5151 {
5152     { WM_SETFONT, sent },
5153     { WM_PAINT, sent },
5154     { WM_ERASEBKGND, sent|defwinproc|optional },
5155     { WM_CTLCOLORBTN, sent|defwinproc },
5156     { 0 }
5157 };
5158
5159 static WNDPROC old_button_proc;
5160
5161 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5162 {
5163     static long defwndproc_counter = 0;
5164     LRESULT ret;
5165     struct recvd_message msg;
5166
5167     if (ignore_message( message )) return 0;
5168
5169     switch (message)
5170     {
5171     case WM_SYNCPAINT:
5172         break;
5173     case BM_SETSTATE:
5174         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5175         /* fall through */
5176     default:
5177         msg.hwnd = hwnd;
5178         msg.message = message;
5179         msg.flags = sent|wparam|lparam;
5180         if (defwndproc_counter) msg.flags |= defwinproc;
5181         msg.wParam = wParam;
5182         msg.lParam = lParam;
5183         msg.descr = "button";
5184         add_message(&msg);
5185     }
5186
5187     defwndproc_counter++;
5188     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5189     defwndproc_counter--;
5190
5191     return ret;
5192 }
5193
5194 static void subclass_button(void)
5195 {
5196     WNDCLASSA cls;
5197
5198     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5199
5200     old_button_proc = cls.lpfnWndProc;
5201
5202     cls.hInstance = GetModuleHandle(0);
5203     cls.lpfnWndProc = button_hook_proc;
5204     cls.lpszClassName = "my_button_class";
5205     UnregisterClass(cls.lpszClassName, cls.hInstance);
5206     if (!RegisterClassA(&cls)) assert(0);
5207 }
5208
5209 static void test_button_messages(void)
5210 {
5211     static const struct
5212     {
5213         DWORD style;
5214         DWORD dlg_code;
5215         const struct message *setfocus;
5216         const struct message *killfocus;
5217     } button[] = {
5218         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5219           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5220         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5221           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5222         { BS_CHECKBOX, DLGC_BUTTON,
5223           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5224         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5225           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5226         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5227           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5228         { BS_3STATE, DLGC_BUTTON,
5229           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5230         { BS_AUTO3STATE, DLGC_BUTTON,
5231           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5232         { BS_GROUPBOX, DLGC_STATIC,
5233           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5234         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5235           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5236         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5237           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5238         { BS_OWNERDRAW, DLGC_BUTTON,
5239           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
5240     };
5241     unsigned int i;
5242     HWND hwnd;
5243     DWORD dlg_code;
5244     HFONT zfont;
5245
5246     /* selection with VK_SPACE should capture button window */
5247     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5248                            0, 0, 50, 14, 0, 0, 0, NULL);
5249     ok(hwnd != 0, "Failed to create button window\n");
5250     ReleaseCapture();
5251     SetFocus(hwnd);
5252     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5253     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5254     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5255     DestroyWindow(hwnd);
5256
5257     subclass_button();
5258
5259     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5260     {
5261         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
5262                                0, 0, 50, 14, 0, 0, 0, NULL);
5263         ok(hwnd != 0, "Failed to create button window\n");
5264
5265         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5266         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5267
5268         ShowWindow(hwnd, SW_SHOW);
5269         UpdateWindow(hwnd);
5270         SetFocus(0);
5271         flush_sequence();
5272
5273         trace("button style %08x\n", button[i].style);
5274         SetFocus(hwnd);
5275         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5276
5277         SetFocus(0);
5278         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5279
5280         DestroyWindow(hwnd);
5281     }
5282
5283     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5284                            0, 0, 50, 14, 0, 0, 0, NULL);
5285     ok(hwnd != 0, "Failed to create button window\n");
5286
5287     SetForegroundWindow(hwnd);
5288     flush_events();
5289
5290     SetActiveWindow(hwnd);
5291     SetFocus(0);
5292     flush_sequence();
5293
5294     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5295     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5296
5297     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5298     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5299
5300     flush_sequence();
5301     zfont = GetStockObject(SYSTEM_FONT);
5302     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5303     UpdateWindow(hwnd);
5304     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5305
5306     DestroyWindow(hwnd);
5307 }
5308
5309 /****************** static message test *************************/
5310 static const struct message WmSetFontStaticSeq[] =
5311 {
5312     { WM_SETFONT, sent },
5313     { WM_PAINT, sent|defwinproc|optional },
5314     { WM_ERASEBKGND, sent|defwinproc|optional },
5315     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5316     { 0 }
5317 };
5318
5319 static WNDPROC old_static_proc;
5320
5321 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5322 {
5323     static long defwndproc_counter = 0;
5324     LRESULT ret;
5325     struct recvd_message msg;
5326
5327     if (ignore_message( message )) return 0;
5328
5329     msg.hwnd = hwnd;
5330     msg.message = message;
5331     msg.flags = sent|wparam|lparam;
5332     if (defwndproc_counter) msg.flags |= defwinproc;
5333     msg.wParam = wParam;
5334     msg.lParam = lParam;
5335     msg.descr = "static";
5336     add_message(&msg);
5337
5338     defwndproc_counter++;
5339     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5340     defwndproc_counter--;
5341
5342     return ret;
5343 }
5344
5345 static void subclass_static(void)
5346 {
5347     WNDCLASSA cls;
5348
5349     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5350
5351     old_static_proc = cls.lpfnWndProc;
5352
5353     cls.hInstance = GetModuleHandle(0);
5354     cls.lpfnWndProc = static_hook_proc;
5355     cls.lpszClassName = "my_static_class";
5356     UnregisterClass(cls.lpszClassName, cls.hInstance);
5357     if (!RegisterClassA(&cls)) assert(0);
5358 }
5359
5360 static void test_static_messages(void)
5361 {
5362     /* FIXME: make as comprehensive as the button message test */
5363     static const struct
5364     {
5365         DWORD style;
5366         DWORD dlg_code;
5367         const struct message *setfont;
5368     } static_ctrl[] = {
5369         { SS_LEFT, DLGC_STATIC,
5370           WmSetFontStaticSeq }
5371     };
5372     unsigned int i;
5373     HWND hwnd;
5374     DWORD dlg_code;
5375
5376     subclass_static();
5377
5378     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5379     {
5380         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5381                                0, 0, 50, 14, 0, 0, 0, NULL);
5382         ok(hwnd != 0, "Failed to create static window\n");
5383
5384         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5385         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5386
5387         ShowWindow(hwnd, SW_SHOW);
5388         UpdateWindow(hwnd);
5389         SetFocus(0);
5390         flush_sequence();
5391
5392         trace("static style %08x\n", static_ctrl[i].style);
5393         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5394         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5395
5396         DestroyWindow(hwnd);
5397     }
5398 }
5399
5400 /****************** ComboBox message test *************************/
5401 #define ID_COMBOBOX 0x000f
5402
5403 static const struct message WmKeyDownComboSeq[] =
5404 {
5405     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5406     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5407     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5408     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5409     { WM_CTLCOLOREDIT, sent|parent },
5410     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5411     { 0 }
5412 };
5413
5414 static WNDPROC old_combobox_proc;
5415
5416 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5417 {
5418     static long defwndproc_counter = 0;
5419     LRESULT ret;
5420     struct recvd_message msg;
5421
5422     /* do not log painting messages */
5423     if (message != WM_PAINT &&
5424         message != WM_NCPAINT &&
5425         message != WM_SYNCPAINT &&
5426         message != WM_ERASEBKGND &&
5427         message != WM_NCHITTEST &&
5428         message != WM_GETTEXT &&
5429         !ignore_message( message ))
5430     {
5431         msg.hwnd = hwnd;
5432         msg.message = message;
5433         msg.flags = sent|wparam|lparam;
5434         if (defwndproc_counter) msg.flags |= defwinproc;
5435         msg.wParam = wParam;
5436         msg.lParam = lParam;
5437         msg.descr = "combo";
5438         add_message(&msg);
5439     }
5440
5441     defwndproc_counter++;
5442     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5443     defwndproc_counter--;
5444
5445     return ret;
5446 }
5447
5448 static void subclass_combobox(void)
5449 {
5450     WNDCLASSA cls;
5451
5452     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5453
5454     old_combobox_proc = cls.lpfnWndProc;
5455
5456     cls.hInstance = GetModuleHandle(0);
5457     cls.lpfnWndProc = combobox_hook_proc;
5458     cls.lpszClassName = "my_combobox_class";
5459     UnregisterClass(cls.lpszClassName, cls.hInstance);
5460     if (!RegisterClassA(&cls)) assert(0);
5461 }
5462
5463 static void test_combobox_messages(void)
5464 {
5465     HWND parent, combo;
5466     LRESULT ret;
5467
5468     subclass_combobox();
5469
5470     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5471                              100, 100, 200, 200, 0, 0, 0, NULL);
5472     ok(parent != 0, "Failed to create parent window\n");
5473     flush_sequence();
5474
5475     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5476                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5477     ok(combo != 0, "Failed to create combobox window\n");
5478
5479     UpdateWindow(combo);
5480
5481     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5482     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5483
5484     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5485     ok(ret == 0, "expected 0, got %ld\n", ret);
5486     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5487     ok(ret == 1, "expected 1, got %ld\n", ret);
5488     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5489     ok(ret == 2, "expected 2, got %ld\n", ret);
5490
5491     SendMessage(combo, CB_SETCURSEL, 0, 0);
5492     SetFocus(combo);
5493     flush_sequence();
5494
5495     log_all_parent_messages++;
5496     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5497     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5498     log_all_parent_messages--;
5499     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5500
5501     DestroyWindow(combo);
5502     DestroyWindow(parent);
5503 }
5504
5505 /****************** WM_IME_KEYDOWN message test *******************/
5506
5507 static const struct message WmImeKeydownMsgSeq_0[] =
5508 {
5509     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5510     { WM_CHAR, wparam, 'A' },
5511     { 0 }
5512 };
5513
5514 static const struct message WmImeKeydownMsgSeq_1[] =
5515 {
5516     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5517     { WM_CHAR,    optional|wparam, VK_RETURN },
5518     { 0 }
5519 };
5520
5521 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5522 {
5523     struct recvd_message msg;
5524
5525     msg.hwnd = hwnd;
5526     msg.message = message;
5527     msg.flags = wparam|lparam;
5528     msg.wParam = wParam;
5529     msg.lParam = lParam;
5530     msg.descr = "wmime_keydown";
5531     add_message(&msg);
5532
5533     return DefWindowProcA(hwnd, message, wParam, lParam);
5534 }
5535
5536 static void register_wmime_keydown_class(void)
5537 {
5538     WNDCLASSA cls;
5539
5540     ZeroMemory(&cls, sizeof(WNDCLASSA));
5541     cls.lpfnWndProc = wmime_keydown_procA;
5542     cls.hInstance = GetModuleHandleA(0);
5543     cls.lpszClassName = "wmime_keydown_class";
5544     if (!RegisterClassA(&cls)) assert(0);
5545 }
5546
5547 static void test_wmime_keydown_message(void)
5548 {
5549     HWND hwnd;
5550     MSG msg;
5551
5552     trace("Message sequences by WM_IME_KEYDOWN\n");
5553
5554     register_wmime_keydown_class();
5555     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5556                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5557                            NULL, NULL, 0);
5558     flush_events();
5559     flush_sequence();
5560
5561     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5562     SendMessage(hwnd, WM_CHAR, 'A', 1);
5563     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5564
5565     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5566     {
5567         TranslateMessage(&msg);
5568         DispatchMessage(&msg);
5569     }
5570     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5571
5572     DestroyWindow(hwnd);
5573 }
5574
5575 /************* painting message test ********************/
5576
5577 void dump_region(HRGN hrgn)
5578 {
5579     DWORD i, size;
5580     RGNDATA *data = NULL;
5581     RECT *rect;
5582
5583     if (!hrgn)
5584     {
5585         printf( "null region\n" );
5586         return;
5587     }
5588     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5589     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5590     GetRegionData( hrgn, size, data );
5591     printf("%d rects:", data->rdh.nCount );
5592     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5593         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5594     printf("\n");
5595     HeapFree( GetProcessHeap(), 0, data );
5596 }
5597
5598 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5599 {
5600     INT ret;
5601     RECT r1, r2;
5602     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5603     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5604
5605     ret = GetUpdateRgn( hwnd, update, FALSE );
5606     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5607     if (ret == NULLREGION)
5608     {
5609         ok( !hrgn, "Update region shouldn't be empty\n" );
5610     }
5611     else
5612     {
5613         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5614         {
5615             ok( 0, "Regions are different\n" );
5616             if (winetest_debug > 0)
5617             {
5618                 printf( "Update region: " );
5619                 dump_region( update );
5620                 printf( "Wanted region: " );
5621                 dump_region( hrgn );
5622             }
5623         }
5624     }
5625     GetRgnBox( update, &r1 );
5626     GetUpdateRect( hwnd, &r2, FALSE );
5627     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5628         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5629         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5630
5631     DeleteObject( tmp );
5632     DeleteObject( update );
5633 }
5634
5635 static const struct message WmInvalidateRgn[] = {
5636     { WM_NCPAINT, sent },
5637     { WM_GETTEXT, sent|defwinproc|optional },
5638     { 0 }
5639 };
5640
5641 static const struct message WmGetUpdateRect[] = {
5642     { WM_NCPAINT, sent },
5643     { WM_GETTEXT, sent|defwinproc|optional },
5644     { WM_PAINT, sent },
5645     { 0 }
5646 };
5647
5648 static const struct message WmInvalidateFull[] = {
5649     { WM_NCPAINT, sent|wparam, 1 },
5650     { WM_GETTEXT, sent|defwinproc|optional },
5651     { 0 }
5652 };
5653
5654 static const struct message WmInvalidateErase[] = {
5655     { WM_NCPAINT, sent|wparam, 1 },
5656     { WM_GETTEXT, sent|defwinproc|optional },
5657     { WM_ERASEBKGND, sent },
5658     { 0 }
5659 };
5660
5661 static const struct message WmInvalidatePaint[] = {
5662     { WM_PAINT, sent },
5663     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5664     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5665     { 0 }
5666 };
5667
5668 static const struct message WmInvalidateErasePaint[] = {
5669     { WM_PAINT, sent },
5670     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5671     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5672     { WM_ERASEBKGND, sent|beginpaint|optional },
5673     { 0 }
5674 };
5675
5676 static const struct message WmInvalidateErasePaint2[] = {
5677     { WM_PAINT, sent },
5678     { WM_NCPAINT, sent|beginpaint },
5679     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5680     { WM_ERASEBKGND, sent|beginpaint|optional },
5681     { 0 }
5682 };
5683
5684 static const struct message WmErase[] = {
5685     { WM_ERASEBKGND, sent },
5686     { 0 }
5687 };
5688
5689 static const struct message WmPaint[] = {
5690     { WM_PAINT, sent },
5691     { 0 }
5692 };
5693
5694 static const struct message WmParentOnlyPaint[] = {
5695     { WM_PAINT, sent|parent },
5696     { 0 }
5697 };
5698
5699 static const struct message WmInvalidateParent[] = {
5700     { WM_NCPAINT, sent|parent },
5701     { WM_GETTEXT, sent|defwinproc|parent|optional },
5702     { WM_ERASEBKGND, sent|parent },
5703     { 0 }
5704 };
5705
5706 static const struct message WmInvalidateParentChild[] = {
5707     { WM_NCPAINT, sent|parent },
5708     { WM_GETTEXT, sent|defwinproc|parent|optional },
5709     { WM_ERASEBKGND, sent|parent },
5710     { WM_NCPAINT, sent },
5711     { WM_GETTEXT, sent|defwinproc|optional },
5712     { WM_ERASEBKGND, sent },
5713     { 0 }
5714 };
5715
5716 static const struct message WmInvalidateParentChild2[] = {
5717     { WM_ERASEBKGND, sent|parent },
5718     { WM_NCPAINT, sent },
5719     { WM_GETTEXT, sent|defwinproc|optional },
5720     { WM_ERASEBKGND, sent },
5721     { 0 }
5722 };
5723
5724 static const struct message WmParentPaint[] = {
5725     { WM_PAINT, sent|parent },
5726     { WM_PAINT, sent },
5727     { 0 }
5728 };
5729
5730 static const struct message WmParentPaintNc[] = {
5731     { WM_PAINT, sent|parent },
5732     { WM_PAINT, sent },
5733     { WM_NCPAINT, sent|beginpaint },
5734     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5735     { WM_ERASEBKGND, sent|beginpaint|optional },
5736     { 0 }
5737 };
5738
5739 static const struct message WmChildPaintNc[] = {
5740     { WM_PAINT, sent },
5741     { WM_NCPAINT, sent|beginpaint },
5742     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5743     { WM_ERASEBKGND, sent|beginpaint|optional },
5744     { 0 }
5745 };
5746
5747 static const struct message WmParentErasePaint[] = {
5748     { WM_PAINT, sent|parent },
5749     { WM_NCPAINT, sent|parent|beginpaint },
5750     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5751     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
5752     { WM_PAINT, sent },
5753     { WM_NCPAINT, sent|beginpaint },
5754     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5755     { WM_ERASEBKGND, sent|beginpaint|optional },
5756     { 0 }
5757 };
5758
5759 static const struct message WmParentOnlyNcPaint[] = {
5760     { WM_PAINT, sent|parent },
5761     { WM_NCPAINT, sent|parent|beginpaint },
5762     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5763     { 0 }
5764 };
5765
5766 static const struct message WmSetParentStyle[] = {
5767     { WM_STYLECHANGING, sent|parent },
5768     { WM_STYLECHANGED, sent|parent },
5769     { 0 }
5770 };
5771
5772 static void test_paint_messages(void)
5773 {
5774     BOOL ret;
5775     RECT rect;
5776     POINT pt;
5777     MSG msg;
5778     HWND hparent, hchild;
5779     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5780     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5781     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5782                                 100, 100, 200, 200, 0, 0, 0, NULL);
5783     ok (hwnd != 0, "Failed to create overlapped window\n");
5784
5785     ShowWindow( hwnd, SW_SHOW );
5786     UpdateWindow( hwnd );
5787     flush_events();
5788     flush_sequence();
5789
5790     check_update_rgn( hwnd, 0 );
5791     SetRectRgn( hrgn, 10, 10, 20, 20 );
5792     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5793     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5794     check_update_rgn( hwnd, hrgn );
5795     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5796     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5797     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5798     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5799     check_update_rgn( hwnd, hrgn );
5800     /* validate everything */
5801     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5802     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5803     check_update_rgn( hwnd, 0 );
5804
5805     /* test empty region */
5806     SetRectRgn( hrgn, 10, 10, 10, 15 );
5807     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5808     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5809     check_update_rgn( hwnd, 0 );
5810     /* test empty rect */
5811     SetRect( &rect, 10, 10, 10, 15 );
5812     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5813     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5814     check_update_rgn( hwnd, 0 );
5815
5816     /* flush pending messages */
5817     flush_events();
5818     flush_sequence();
5819
5820     GetClientRect( hwnd, &rect );
5821     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5822     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5823      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5824      */
5825     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5826     SetRectEmpty( &rect );
5827     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5828     check_update_rgn( hwnd, hrgn );
5829     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5830     flush_events();
5831     ok_sequence( WmPaint, "Paint", FALSE );
5832     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5833     check_update_rgn( hwnd, 0 );
5834
5835     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5836      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5837      */
5838     trace("testing ValidateRect(0, NULL)\n");
5839     SetRectEmpty( &rect );
5840     if (ValidateRect(0, &rect))  /* not supported on Win9x */
5841     {
5842         check_update_rgn( hwnd, hrgn );
5843         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5844         flush_events();
5845         ok_sequence( WmPaint, "Paint", FALSE );
5846         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5847         check_update_rgn( hwnd, 0 );
5848     }
5849
5850     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5851     SetLastError(0xdeadbeef);
5852     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5853     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5854        "wrong error code %d\n", GetLastError());
5855     check_update_rgn( hwnd, 0 );
5856     flush_events();
5857     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5858
5859     trace("testing ValidateRgn(0, NULL)\n");
5860     SetLastError(0xdeadbeef);
5861     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5862     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
5863        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
5864        "wrong error code %d\n", GetLastError());
5865     check_update_rgn( hwnd, 0 );
5866     flush_events();
5867     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5868
5869     /* now with frame */
5870     SetRectRgn( hrgn, -5, -5, 20, 20 );
5871
5872     /* flush pending messages */
5873     flush_events();
5874     flush_sequence();
5875     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5876     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5877
5878     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5879     check_update_rgn( hwnd, hrgn );
5880
5881     flush_sequence();
5882     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5883     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5884
5885     flush_sequence();
5886     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5887     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5888
5889     GetClientRect( hwnd, &rect );
5890     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5891     check_update_rgn( hwnd, hrgn );
5892
5893     flush_sequence();
5894     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5895     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5896
5897     flush_sequence();
5898     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5899     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5900     check_update_rgn( hwnd, 0 );
5901
5902     flush_sequence();
5903     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5904     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5905     check_update_rgn( hwnd, 0 );
5906
5907     flush_sequence();
5908     SetRectRgn( hrgn, 0, 0, 100, 100 );
5909     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5910     SetRectRgn( hrgn, 0, 0, 50, 100 );
5911     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5912     SetRectRgn( hrgn, 50, 0, 100, 100 );
5913     check_update_rgn( hwnd, hrgn );
5914     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5915     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5916     check_update_rgn( hwnd, 0 );
5917
5918     flush_sequence();
5919     SetRectRgn( hrgn, 0, 0, 100, 100 );
5920     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5921     SetRectRgn( hrgn, 0, 0, 100, 50 );
5922     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5923     ok_sequence( WmErase, "Erase", FALSE );
5924     SetRectRgn( hrgn, 0, 50, 100, 100 );
5925     check_update_rgn( hwnd, hrgn );
5926
5927     flush_sequence();
5928     SetRectRgn( hrgn, 0, 0, 100, 100 );
5929     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5930     SetRectRgn( hrgn, 0, 0, 50, 50 );
5931     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5932     ok_sequence( WmPaint, "Paint", FALSE );
5933
5934     flush_sequence();
5935     SetRectRgn( hrgn, -4, -4, -2, -2 );
5936     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5937     SetRectRgn( hrgn, -200, -200, -198, -198 );
5938     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5939     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5940
5941     flush_sequence();
5942     SetRectRgn( hrgn, -4, -4, -2, -2 );
5943     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5944     SetRectRgn( hrgn, -4, -4, -3, -3 );
5945     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5946     SetRectRgn( hrgn, 0, 0, 1, 1 );
5947     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5948     ok_sequence( WmPaint, "Paint", FALSE );
5949
5950     flush_sequence();
5951     SetRectRgn( hrgn, -4, -4, -1, -1 );
5952     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5953     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5954     /* make sure no WM_PAINT was generated */
5955     flush_events();
5956     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5957
5958     flush_sequence();
5959     SetRectRgn( hrgn, -4, -4, -1, -1 );
5960     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5961     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5962     {
5963         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5964         {
5965             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5966             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5967             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5968             ret = GetUpdateRect( hwnd, &rect, FALSE );
5969             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5970             /* this will send WM_NCPAINT and validate the non client area */
5971             ret = GetUpdateRect( hwnd, &rect, TRUE );
5972             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5973         }
5974         DispatchMessage( &msg );
5975     }
5976     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5977
5978     DestroyWindow( hwnd );
5979
5980     /* now test with a child window */
5981
5982     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5983                               100, 100, 200, 200, 0, 0, 0, NULL);
5984     ok (hparent != 0, "Failed to create parent window\n");
5985
5986     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5987                            10, 10, 100, 100, hparent, 0, 0, NULL);
5988     ok (hchild != 0, "Failed to create child window\n");
5989
5990     ShowWindow( hparent, SW_SHOW );
5991     UpdateWindow( hparent );
5992     UpdateWindow( hchild );
5993     flush_events();
5994     flush_sequence();
5995     log_all_parent_messages++;
5996
5997     SetRect( &rect, 0, 0, 50, 50 );
5998     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5999     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6000     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6001
6002     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6003     pt.x = pt.y = 0;
6004     MapWindowPoints( hchild, hparent, &pt, 1 );
6005     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6006     check_update_rgn( hchild, hrgn );
6007     SetRectRgn( hrgn, 0, 0, 50, 50 );
6008     check_update_rgn( hparent, hrgn );
6009     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6010     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6011     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6012     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6013
6014     flush_events();
6015     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6016
6017     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6018     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6019     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6020     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6021     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6022
6023     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6024     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6025     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6026
6027     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6028     flush_sequence();
6029     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6030     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6031     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6032
6033     /* flush all paint messages */
6034     flush_events();
6035     flush_sequence();
6036
6037     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6038     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6039     SetRectRgn( hrgn, 0, 0, 50, 50 );
6040     check_update_rgn( hparent, hrgn );
6041     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6042     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6043     SetRectRgn( hrgn, 0, 0, 50, 50 );
6044     check_update_rgn( hparent, hrgn );
6045
6046     /* flush all paint messages */
6047     flush_events();
6048     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6049     flush_sequence();
6050
6051     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6052     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6053     SetRectRgn( hrgn, 0, 0, 50, 50 );
6054     check_update_rgn( hparent, hrgn );
6055     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6056     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6057     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6058     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6059     check_update_rgn( hparent, hrgn );
6060     /* flush all paint messages */
6061     flush_events();
6062     flush_sequence();
6063
6064     /* same as above but parent gets completely validated */
6065     SetRect( &rect, 20, 20, 30, 30 );
6066     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6067     SetRectRgn( hrgn, 20, 20, 30, 30 );
6068     check_update_rgn( hparent, hrgn );
6069     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6070     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6071     check_update_rgn( hparent, 0 );  /* no update region */
6072     flush_events();
6073     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6074
6075     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6076     flush_sequence();
6077     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6078     SetRectRgn( hrgn, 20, 20, 30, 30 );
6079     check_update_rgn( hparent, hrgn );
6080     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6081     SetRectRgn( hrgn, 20, 20, 30, 30 );
6082     check_update_rgn( hparent, hrgn );
6083
6084     /* same as above but normal WM_PAINT doesn't validate parent */
6085     flush_sequence();
6086     SetRect( &rect, 20, 20, 30, 30 );
6087     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6088     SetRectRgn( hrgn, 20, 20, 30, 30 );
6089     check_update_rgn( hparent, hrgn );
6090     /* no WM_PAINT in child while parent still pending */
6091     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6092     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6093     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6094     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6095
6096     flush_sequence();
6097     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6098     /* no WM_PAINT in child while parent still pending */
6099     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6100     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6101     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6102     /* now that parent is valid child should get WM_PAINT */
6103     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6104     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6105     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6106     ok_sequence( WmEmptySeq, "No other message", FALSE );
6107
6108     /* same thing with WS_CLIPCHILDREN in parent */
6109     flush_sequence();
6110     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6111     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6112     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6113     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6114     ok_sequence( WmEmptySeq, "No message", FALSE );
6115     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6116     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6117
6118     flush_sequence();
6119     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6120     SetRectRgn( hrgn, 20, 20, 30, 30 );
6121     check_update_rgn( hparent, hrgn );
6122     /* no WM_PAINT in child while parent still pending */
6123     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6124     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6125     /* WM_PAINT in parent first */
6126     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6127     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6128
6129     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6130     flush_sequence();
6131     SetRect( &rect, 0, 0, 30, 30 );
6132     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6133     SetRectRgn( hrgn, 0, 0, 30, 30 );
6134     check_update_rgn( hparent, hrgn );
6135     flush_events();
6136     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6137
6138     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6139     flush_sequence();
6140     SetRect( &rect, -10, 0, 30, 30 );
6141     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6142     SetRect( &rect, 0, 0, 20, 20 );
6143     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6144     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6145     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6146
6147     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6148     flush_sequence();
6149     SetRect( &rect, -10, 0, 30, 30 );
6150     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6151     SetRect( &rect, 0, 0, 100, 100 );
6152     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6153     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6154     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6155     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6156     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6157
6158     /* test RDW_INTERNALPAINT behavior */
6159
6160     flush_sequence();
6161     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6162     flush_events();
6163     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6164
6165     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6166     flush_events();
6167     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6168
6169     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6170     flush_events();
6171     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6172
6173     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6174     UpdateWindow( hparent );
6175     flush_events();
6176     flush_sequence();
6177     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6178     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6179     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6180                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6181     flush_events();
6182     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6183
6184     UpdateWindow( hparent );
6185     flush_events();
6186     flush_sequence();
6187     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6188     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6189     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6190                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6191     flush_events();
6192     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6193
6194     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6195     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6196     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6197     flush_events();
6198     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6199
6200     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6201     UpdateWindow( hparent );
6202     flush_events();
6203     flush_sequence();
6204     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6205     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6206     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6207                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6208     flush_events();
6209     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6210
6211     UpdateWindow( hparent );
6212     flush_events();
6213     flush_sequence();
6214     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6215     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6216     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6217                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6218     flush_events();
6219     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6220
6221     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6222     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6223
6224     UpdateWindow( hparent );
6225     flush_events();
6226     flush_sequence();
6227     trace("testing SetWindowPos(-10000, -10000) on child\n");
6228     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6229     check_update_rgn( hchild, 0 );
6230     flush_events();
6231
6232 #if 0 /* this one doesn't pass under Wine yet */
6233     UpdateWindow( hparent );
6234     flush_events();
6235     flush_sequence();
6236     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6237     ShowWindow( hchild, SW_MINIMIZE );
6238     check_update_rgn( hchild, 0 );
6239     flush_events();
6240 #endif
6241
6242     UpdateWindow( hparent );
6243     flush_events();
6244     flush_sequence();
6245     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6246     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6247     check_update_rgn( hparent, 0 );
6248     flush_events();
6249
6250     log_all_parent_messages--;
6251     DestroyWindow( hparent );
6252     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6253
6254     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6255
6256     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6257                               100, 100, 200, 200, 0, 0, 0, NULL);
6258     ok (hparent != 0, "Failed to create parent window\n");
6259
6260     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6261                            10, 10, 100, 100, hparent, 0, 0, NULL);
6262     ok (hchild != 0, "Failed to create child window\n");
6263
6264     ShowWindow( hparent, SW_SHOW );
6265     UpdateWindow( hparent );
6266     UpdateWindow( hchild );
6267     flush_events();
6268     flush_sequence();
6269
6270     /* moving child outside of parent boundaries changes update region */
6271     SetRect( &rect, 0, 0, 40, 40 );
6272     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6273     SetRectRgn( hrgn, 0, 0, 40, 40 );
6274     check_update_rgn( hchild, hrgn );
6275     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6276     SetRectRgn( hrgn, 10, 0, 40, 40 );
6277     check_update_rgn( hchild, hrgn );
6278     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6279     SetRectRgn( hrgn, 10, 10, 40, 40 );
6280     check_update_rgn( hchild, hrgn );
6281
6282     /* moving parent off-screen does too */
6283     SetRect( &rect, 0, 0, 100, 100 );
6284     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6285     SetRectRgn( hrgn, 0, 0, 100, 100 );
6286     check_update_rgn( hparent, hrgn );
6287     SetRectRgn( hrgn, 10, 10, 40, 40 );
6288     check_update_rgn( hchild, hrgn );
6289     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6290     SetRectRgn( hrgn, 20, 20, 100, 100 );
6291     check_update_rgn( hparent, hrgn );
6292     SetRectRgn( hrgn, 30, 30, 40, 40 );
6293     check_update_rgn( hchild, hrgn );
6294
6295     /* invalidated region is cropped by the parent rects */
6296     SetRect( &rect, 0, 0, 50, 50 );
6297     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6298     SetRectRgn( hrgn, 30, 30, 50, 50 );
6299     check_update_rgn( hchild, hrgn );
6300
6301     DestroyWindow( hparent );
6302     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6303     flush_sequence();
6304
6305     DeleteObject( hrgn );
6306     DeleteObject( hrgn2 );
6307 }
6308
6309 struct wnd_event
6310 {
6311     HWND hwnd;
6312     HANDLE event;
6313 };
6314
6315 static DWORD WINAPI thread_proc(void *param)
6316 {
6317     MSG msg;
6318     struct wnd_event *wnd_event = param;
6319
6320     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6321                                       100, 100, 200, 200, 0, 0, 0, NULL);
6322     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6323
6324     SetEvent(wnd_event->event);
6325
6326     while (GetMessage(&msg, 0, 0, 0))
6327     {
6328         TranslateMessage(&msg);
6329         DispatchMessage(&msg);
6330     }
6331
6332     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6333
6334     return 0;
6335 }
6336
6337 static void test_interthread_messages(void)
6338 {
6339     HANDLE hThread;
6340     DWORD tid;
6341     WNDPROC proc;
6342     MSG msg;
6343     char buf[256];
6344     int len, expected_len;
6345     struct wnd_event wnd_event;
6346     BOOL ret;
6347
6348     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
6349     if (!wnd_event.event)
6350     {
6351         win_skip("skipping interthread message test under win9x\n");
6352         return;
6353     }
6354
6355     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6356     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6357
6358     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6359
6360     CloseHandle(wnd_event.event);
6361
6362     SetLastError(0xdeadbeef);
6363     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6364     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6365        "wrong error code %d\n", GetLastError());
6366
6367     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6368     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6369
6370     expected_len = lstrlenA("window caption text");
6371     memset(buf, 0, sizeof(buf));
6372     SetLastError(0xdeadbeef);
6373     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6374     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6375     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6376
6377     msg.hwnd = wnd_event.hwnd;
6378     msg.message = WM_GETTEXT;
6379     msg.wParam = sizeof(buf);
6380     msg.lParam = (LPARAM)buf;
6381     memset(buf, 0, sizeof(buf));
6382     SetLastError(0xdeadbeef);
6383     len = DispatchMessageA(&msg);
6384     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6385        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6386
6387     /* the following test causes an exception in user.exe under win9x */
6388     msg.hwnd = wnd_event.hwnd;
6389     msg.message = WM_TIMER;
6390     msg.wParam = 0;
6391     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6392     SetLastError(0xdeadbeef);
6393     len = DispatchMessageA(&msg);
6394     ok(!len && GetLastError() == 0xdeadbeef,
6395        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6396
6397     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6398     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6399
6400     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6401     CloseHandle(hThread);
6402
6403     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6404 }
6405
6406
6407 static const struct message WmVkN[] = {
6408     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6409     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6410     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6411     { WM_CHAR, wparam|lparam, 'n', 1 },
6412     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6413     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6414     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6415     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6416     { 0 }
6417 };
6418 static const struct message WmShiftVkN[] = {
6419     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6420     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6421     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6422     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6423     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6424     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6425     { WM_CHAR, wparam|lparam, 'N', 1 },
6426     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6427     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6428     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6429     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6430     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6431     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6432     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6433     { 0 }
6434 };
6435 static const struct message WmCtrlVkN[] = {
6436     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6437     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6438     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6439     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6440     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6441     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6442     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6443     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6444     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6445     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6446     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6447     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6448     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6449     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6450     { 0 }
6451 };
6452 static const struct message WmCtrlVkN_2[] = {
6453     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6454     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6455     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6456     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6457     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6458     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6459     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6460     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6461     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6462     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6463     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6464     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6465     { 0 }
6466 };
6467 static const struct message WmAltVkN[] = {
6468     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6469     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6470     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6471     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6472     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6473     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6474     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6475     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6476     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6477     { HCBT_SYSCOMMAND, hook },
6478     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6479     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6480     { 0x00AE, sent|defwinproc|optional }, /* XP */
6481     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6482     { WM_INITMENU, sent|defwinproc },
6483     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6484     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6485     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6486     { WM_CAPTURECHANGED, sent|defwinproc },
6487     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6488     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6489     { WM_EXITMENULOOP, sent|defwinproc },
6490     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6491     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6492     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6493     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6494     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6495     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6496     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6497     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6498     { 0 }
6499 };
6500 static const struct message WmAltVkN_2[] = {
6501     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6502     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6503     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6504     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6505     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6506     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6507     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6508     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6509     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6510     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6511     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6512     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6513     { 0 }
6514 };
6515 static const struct message WmCtrlAltVkN[] = {
6516     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6517     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6518     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6519     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6520     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6521     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6522     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6523     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6524     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6525     { WM_CHAR, optional },
6526     { WM_CHAR, sent|optional },
6527     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6528     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6529     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6530     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6531     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6532     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6533     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6534     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6535     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6536     { 0 }
6537 };
6538 static const struct message WmCtrlShiftVkN[] = {
6539     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6540     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6541     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6542     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6543     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6544     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6545     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6546     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6547     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6548     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6549     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6550     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6551     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6552     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6553     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6554     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6555     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6556     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6557     { 0 }
6558 };
6559 static const struct message WmCtrlAltShiftVkN[] = {
6560     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6561     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6562     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6563     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6564     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6565     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6566     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6567     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6568     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6569     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6570     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6571     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6572     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6573     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6574     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6575     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6576     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6577     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6578     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6579     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6580     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6581     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6582     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6583     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6584     { 0 }
6585 };
6586 static const struct message WmAltPressRelease[] = {
6587     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6588     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6589     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6590     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6591     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6592     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6593     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6594     { HCBT_SYSCOMMAND, hook },
6595     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6596     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6597     { WM_INITMENU, sent|defwinproc },
6598     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6599     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6600     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6601
6602     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6603
6604     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6605     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6606     { WM_CAPTURECHANGED, sent|defwinproc },
6607     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6608     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6609     { WM_EXITMENULOOP, sent|defwinproc },
6610     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6611     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6612     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6613     { 0 }
6614 };
6615 static const struct message WmShiftMouseButton[] = {
6616     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6617     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6618     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6619     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6620     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6621     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
6622     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
6623     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
6624     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
6625     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6626     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6627     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6628     { 0 }
6629 };
6630 static const struct message WmF1Seq[] = {
6631     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6632     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6633     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6634     { WM_KEYF1, wparam|lparam, 0, 0 },
6635     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6636     { WM_HELP, sent|defwinproc },
6637     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6638     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6639     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6640     { 0 }
6641 };
6642 static const struct message WmVkAppsSeq[] = {
6643     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6644     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6645     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6646     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6647     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6648     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6649     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6650     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6651     { 0 }
6652 };
6653
6654 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6655 {
6656     MSG msg;
6657
6658     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6659     {
6660         struct recvd_message log_msg;
6661
6662         /* ignore some unwanted messages */
6663         if (msg.message == WM_MOUSEMOVE ||
6664             msg.message == WM_TIMER ||
6665             ignore_message( msg.message ))
6666             continue;
6667
6668         log_msg.hwnd = msg.hwnd;
6669         log_msg.message = msg.message;
6670         log_msg.flags = wparam|lparam;
6671         log_msg.wParam = msg.wParam;
6672         log_msg.lParam = msg.lParam;
6673         log_msg.descr = "accel";
6674         add_message(&log_msg);
6675
6676         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6677         {
6678             TranslateMessage(&msg);
6679             DispatchMessage(&msg);
6680         }
6681     }
6682 }
6683
6684 static void test_accelerators(void)
6685 {
6686     RECT rc;
6687     POINT pt;
6688     SHORT state;
6689     HACCEL hAccel;
6690     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6691                                 100, 100, 200, 200, 0, 0, 0, NULL);
6692     BOOL ret;
6693
6694     assert(hwnd != 0);
6695     UpdateWindow(hwnd);
6696     flush_events();
6697     flush_sequence();
6698
6699     SetFocus(hwnd);
6700     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6701
6702     state = GetKeyState(VK_SHIFT);
6703     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6704     state = GetKeyState(VK_CAPITAL);
6705     ok(state == 0, "wrong CapsLock state %04x\n", state);
6706
6707     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6708     assert(hAccel != 0);
6709
6710     flush_events();
6711     pump_msg_loop(hwnd, 0);
6712     flush_sequence();
6713
6714     trace("testing VK_N press/release\n");
6715     flush_sequence();
6716     keybd_event('N', 0, 0, 0);
6717     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6718     pump_msg_loop(hwnd, hAccel);
6719     if (!sequence_cnt)  /* we didn't get any message */
6720     {
6721         skip( "queuing key events not supported\n" );
6722         goto done;
6723     }
6724     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6725
6726     trace("testing Shift+VK_N press/release\n");
6727     flush_sequence();
6728     keybd_event(VK_SHIFT, 0, 0, 0);
6729     keybd_event('N', 0, 0, 0);
6730     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6731     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6732     pump_msg_loop(hwnd, hAccel);
6733     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6734
6735     trace("testing Ctrl+VK_N press/release\n");
6736     flush_sequence();
6737     keybd_event(VK_CONTROL, 0, 0, 0);
6738     keybd_event('N', 0, 0, 0);
6739     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6740     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6741     pump_msg_loop(hwnd, hAccel);
6742     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6743
6744     trace("testing Alt+VK_N press/release\n");
6745     flush_sequence();
6746     keybd_event(VK_MENU, 0, 0, 0);
6747     keybd_event('N', 0, 0, 0);
6748     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6749     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6750     pump_msg_loop(hwnd, hAccel);
6751     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6752
6753     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6754     flush_sequence();
6755     keybd_event(VK_CONTROL, 0, 0, 0);
6756     keybd_event(VK_MENU, 0, 0, 0);
6757     keybd_event('N', 0, 0, 0);
6758     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6759     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6760     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6761     pump_msg_loop(hwnd, hAccel);
6762     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6763
6764     ret = DestroyAcceleratorTable(hAccel);
6765     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6766
6767     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6768     assert(hAccel != 0);
6769
6770     trace("testing VK_N press/release\n");
6771     flush_sequence();
6772     keybd_event('N', 0, 0, 0);
6773     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6774     pump_msg_loop(hwnd, hAccel);
6775     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6776
6777     trace("testing Shift+VK_N press/release\n");
6778     flush_sequence();
6779     keybd_event(VK_SHIFT, 0, 0, 0);
6780     keybd_event('N', 0, 0, 0);
6781     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6782     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6783     pump_msg_loop(hwnd, hAccel);
6784     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6785
6786     trace("testing Ctrl+VK_N press/release 2\n");
6787     flush_sequence();
6788     keybd_event(VK_CONTROL, 0, 0, 0);
6789     keybd_event('N', 0, 0, 0);
6790     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6791     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6792     pump_msg_loop(hwnd, hAccel);
6793     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6794
6795     trace("testing Alt+VK_N press/release 2\n");
6796     flush_sequence();
6797     keybd_event(VK_MENU, 0, 0, 0);
6798     keybd_event('N', 0, 0, 0);
6799     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6800     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6801     pump_msg_loop(hwnd, hAccel);
6802     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6803
6804     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6805     flush_sequence();
6806     keybd_event(VK_CONTROL, 0, 0, 0);
6807     keybd_event(VK_MENU, 0, 0, 0);
6808     keybd_event('N', 0, 0, 0);
6809     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6810     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6811     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6812     pump_msg_loop(hwnd, hAccel);
6813     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6814
6815     trace("testing Ctrl+Shift+VK_N press/release\n");
6816     flush_sequence();
6817     keybd_event(VK_CONTROL, 0, 0, 0);
6818     keybd_event(VK_SHIFT, 0, 0, 0);
6819     keybd_event('N', 0, 0, 0);
6820     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6821     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6822     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6823     pump_msg_loop(hwnd, hAccel);
6824     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6825
6826     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6827     flush_sequence();
6828     keybd_event(VK_CONTROL, 0, 0, 0);
6829     keybd_event(VK_MENU, 0, 0, 0);
6830     keybd_event(VK_SHIFT, 0, 0, 0);
6831     keybd_event('N', 0, 0, 0);
6832     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6833     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6834     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6835     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6836     pump_msg_loop(hwnd, hAccel);
6837     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6838
6839     ret = DestroyAcceleratorTable(hAccel);
6840     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6841     hAccel = 0;
6842
6843     trace("testing Alt press/release\n");
6844     flush_sequence();
6845     keybd_event(VK_MENU, 0, 0, 0);
6846     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6847     keybd_event(VK_MENU, 0, 0, 0);
6848     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6849     pump_msg_loop(hwnd, 0);
6850     /* this test doesn't pass in Wine for managed windows */
6851     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6852
6853     trace("testing VK_F1 press/release\n");
6854     keybd_event(VK_F1, 0, 0, 0);
6855     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6856     pump_msg_loop(hwnd, 0);
6857     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6858
6859     trace("testing VK_APPS press/release\n");
6860     keybd_event(VK_APPS, 0, 0, 0);
6861     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6862     pump_msg_loop(hwnd, 0);
6863     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6864
6865     trace("testing Shift+MouseButton press/release\n");
6866     /* first, move mouse pointer inside of the window client area */
6867     GetClientRect(hwnd, &rc);
6868     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6869     rc.left += (rc.right - rc.left)/2;
6870     rc.top += (rc.bottom - rc.top)/2;
6871     SetCursorPos(rc.left, rc.top);
6872     SetActiveWindow(hwnd);
6873
6874     flush_events();
6875     flush_sequence();
6876     GetCursorPos(&pt);
6877     if (pt.x == rc.left && pt.y == rc.top)
6878     {
6879         int i;
6880         keybd_event(VK_SHIFT, 0, 0, 0);
6881         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6882         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6883         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6884         pump_msg_loop(hwnd, 0);
6885         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
6886         if (i < sequence_cnt)
6887             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
6888         else
6889             skip( "Shift+MouseButton event didn't get to the window\n" );
6890     }
6891
6892 done:
6893     if (hAccel) DestroyAcceleratorTable(hAccel);
6894     DestroyWindow(hwnd);
6895 }
6896
6897 /************* window procedures ********************/
6898
6899 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6900                              WPARAM wParam, LPARAM lParam)
6901 {
6902     static LONG defwndproc_counter = 0;
6903     static LONG beginpaint_counter = 0;
6904     LRESULT ret;
6905     struct recvd_message msg;
6906
6907     if (ignore_message( message )) return 0;
6908
6909     switch (message)
6910     {
6911         case WM_ENABLE:
6912         {
6913             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6914             ok((BOOL)wParam == !(style & WS_DISABLED),
6915                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6916             break;
6917         }
6918
6919         case WM_CAPTURECHANGED:
6920             if (test_DestroyWindow_flag)
6921             {
6922                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6923                 if (style & WS_CHILD)
6924                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6925                 else if (style & WS_POPUP)
6926                     lParam = WND_POPUP_ID;
6927                 else
6928                     lParam = WND_PARENT_ID;
6929             }
6930             break;
6931
6932         case WM_NCDESTROY:
6933         {
6934             HWND capture;
6935
6936             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6937             capture = GetCapture();
6938             if (capture)
6939             {
6940                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6941                 trace("current capture %p, releasing...\n", capture);
6942                 ReleaseCapture();
6943             }
6944         }
6945         /* fall through */
6946         case WM_DESTROY:
6947             if (pGetAncestor)
6948                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6949             if (test_DestroyWindow_flag)
6950             {
6951                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6952                 if (style & WS_CHILD)
6953                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6954                 else if (style & WS_POPUP)
6955                     lParam = WND_POPUP_ID;
6956                 else
6957                     lParam = WND_PARENT_ID;
6958             }
6959             break;
6960
6961         /* test_accelerators() depends on this */
6962         case WM_NCHITTEST:
6963             return HTCLIENT;
6964
6965         /* ignore */
6966         case WM_MOUSEMOVE:
6967         case WM_MOUSEACTIVATE:
6968         case WM_NCMOUSEMOVE:
6969         case WM_SETCURSOR:
6970         case WM_IME_SELECT:
6971             return 0;
6972     }
6973
6974     msg.hwnd = hwnd;
6975     msg.message = message;
6976     msg.flags = sent|wparam|lparam;
6977     if (defwndproc_counter) msg.flags |= defwinproc;
6978     if (beginpaint_counter) msg.flags |= beginpaint;
6979     msg.wParam = wParam;
6980     msg.lParam = lParam;
6981     msg.descr = "MsgCheckProc";
6982     add_message(&msg);
6983
6984     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6985     {
6986         HWND parent = GetParent(hwnd);
6987         RECT rc;
6988         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6989
6990         GetClientRect(parent, &rc);
6991         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6992         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
6993               minmax->ptReserved.x, minmax->ptReserved.y,
6994               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6995               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6996               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6997               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6998
6999         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7000            minmax->ptMaxSize.x, rc.right);
7001         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7002            minmax->ptMaxSize.y, rc.bottom);
7003     }
7004
7005     if (message == WM_PAINT)
7006     {
7007         PAINTSTRUCT ps;
7008         beginpaint_counter++;
7009         BeginPaint( hwnd, &ps );
7010         beginpaint_counter--;
7011         EndPaint( hwnd, &ps );
7012         return 0;
7013     }
7014
7015     defwndproc_counter++;
7016     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7017                   : DefWindowProcA(hwnd, message, wParam, lParam);
7018     defwndproc_counter--;
7019
7020     return ret;
7021 }
7022
7023 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7024 {
7025     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7026 }
7027
7028 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7029 {
7030     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7031 }
7032
7033 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7034 {
7035     static LONG defwndproc_counter = 0;
7036     LRESULT ret;
7037     struct recvd_message msg;
7038
7039     if (ignore_message( message )) return 0;
7040
7041     switch (message)
7042     {
7043     case WM_QUERYENDSESSION:
7044     case WM_ENDSESSION:
7045         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7046         break;
7047     }
7048
7049     msg.hwnd = hwnd;
7050     msg.message = message;
7051     msg.flags = sent|wparam|lparam;
7052     if (defwndproc_counter) msg.flags |= defwinproc;
7053     msg.wParam = wParam;
7054     msg.lParam = lParam;
7055     msg.descr = "popup";
7056     add_message(&msg);
7057
7058     if (message == WM_CREATE)
7059     {
7060         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7061         SetWindowLongA(hwnd, GWL_STYLE, style);
7062     }
7063
7064     defwndproc_counter++;
7065     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7066     defwndproc_counter--;
7067
7068     return ret;
7069 }
7070
7071 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7072 {
7073     static LONG defwndproc_counter = 0;
7074     static LONG beginpaint_counter = 0;
7075     LRESULT ret;
7076     struct recvd_message msg;
7077
7078     if (ignore_message( message )) return 0;
7079
7080     if (log_all_parent_messages ||
7081         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7082         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7083         message == WM_ENABLE || message == WM_ENTERIDLE ||
7084         message == WM_DRAWITEM ||
7085         message == WM_IME_SETCONTEXT)
7086     {
7087         switch (message)
7088         {
7089             /* ignore */
7090             case WM_NCHITTEST:
7091                 return HTCLIENT;
7092             case WM_SETCURSOR:
7093             case WM_MOUSEMOVE:
7094             case WM_NCMOUSEMOVE:
7095                 return 0;
7096
7097             case WM_ERASEBKGND:
7098             {
7099                 RECT rc;
7100                 INT ret = GetClipBox((HDC)wParam, &rc);
7101
7102                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7103                        ret, rc.left, rc.top, rc.right, rc.bottom);
7104                 break;
7105             }
7106         }
7107
7108         msg.hwnd = hwnd;
7109         msg.message = message;
7110         msg.flags = sent|parent|wparam|lparam;
7111         if (defwndproc_counter) msg.flags |= defwinproc;
7112         if (beginpaint_counter) msg.flags |= beginpaint;
7113         msg.wParam = wParam;
7114         msg.lParam = lParam;
7115         msg.descr = "parent";
7116         add_message(&msg);
7117     }
7118
7119     if (message == WM_PAINT)
7120     {
7121         PAINTSTRUCT ps;
7122         beginpaint_counter++;
7123         BeginPaint( hwnd, &ps );
7124         beginpaint_counter--;
7125         EndPaint( hwnd, &ps );
7126         return 0;
7127     }
7128
7129     defwndproc_counter++;
7130     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7131     defwndproc_counter--;
7132
7133     return ret;
7134 }
7135
7136 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7137 {
7138     static LONG defwndproc_counter = 0;
7139     LRESULT ret;
7140     struct recvd_message msg;
7141
7142     if (ignore_message( message )) return 0;
7143
7144     if (test_def_id)
7145     {
7146         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7147         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7148         if (after_end_dialog)
7149             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7150         else
7151             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7152     }
7153
7154     msg.hwnd = hwnd;
7155     msg.message = message;
7156     msg.flags = sent|wparam|lparam;
7157     if (defwndproc_counter) msg.flags |= defwinproc;
7158     msg.wParam = wParam;
7159     msg.lParam = lParam;
7160     msg.descr = "dialog";
7161     add_message(&msg);
7162
7163     defwndproc_counter++;
7164     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7165     defwndproc_counter--;
7166
7167     return ret;
7168 }
7169
7170 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7171 {
7172     static LONG defwndproc_counter = 0;
7173     LRESULT ret;
7174     struct recvd_message msg;
7175
7176     /* log only specific messages we are interested in */
7177     switch (message)
7178     {
7179 #if 0 /* probably log these as well */
7180     case WM_ACTIVATE:
7181     case WM_SETFOCUS:
7182     case WM_KILLFOCUS:
7183 #endif
7184     case WM_SHOWWINDOW:
7185     case WM_SIZE:
7186     case WM_MOVE:
7187     case WM_GETMINMAXINFO:
7188     case WM_WINDOWPOSCHANGING:
7189     case WM_WINDOWPOSCHANGED:
7190         break;
7191
7192     default: /* ignore */
7193         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7194         return DefWindowProcA(hwnd, message, wParam, lParam);
7195     }
7196
7197     msg.hwnd = hwnd;
7198     msg.message = message;
7199     msg.flags = sent|wparam|lparam;
7200     if (defwndproc_counter) msg.flags |= defwinproc;
7201     msg.wParam = wParam;
7202     msg.lParam = lParam;
7203     msg.descr = "show";
7204     add_message(&msg);
7205
7206     defwndproc_counter++;
7207     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7208     defwndproc_counter--;
7209
7210     return ret;
7211 }
7212
7213 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7214 {
7215     switch (msg)
7216     {
7217         case WM_CREATE: return 0;
7218         case WM_PAINT:
7219         {
7220             MSG msg2;
7221             static int i = 0;
7222
7223             if (i < 256)
7224             {
7225                 i++;
7226                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7227                 {
7228                     TranslateMessage(&msg2);
7229                     DispatchMessage(&msg2);
7230                 }
7231                 i--;
7232             }
7233             else ok(broken(1), "infinite loop\n");
7234             if ( i == 0)
7235                 paint_loop_done = 1;
7236             return DefWindowProcA(hWnd,msg,wParam,lParam);
7237         }
7238     }
7239     return DefWindowProcA(hWnd,msg,wParam,lParam);
7240 }
7241
7242 static BOOL RegisterWindowClasses(void)
7243 {
7244     WNDCLASSA cls;
7245     WNDCLASSW clsW;
7246
7247     cls.style = 0;
7248     cls.lpfnWndProc = MsgCheckProcA;
7249     cls.cbClsExtra = 0;
7250     cls.cbWndExtra = 0;
7251     cls.hInstance = GetModuleHandleA(0);
7252     cls.hIcon = 0;
7253     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7254     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7255     cls.lpszMenuName = NULL;
7256     cls.lpszClassName = "TestWindowClass";
7257     if(!RegisterClassA(&cls)) return FALSE;
7258
7259     cls.lpfnWndProc = ShowWindowProcA;
7260     cls.lpszClassName = "ShowWindowClass";
7261     if(!RegisterClassA(&cls)) return FALSE;
7262
7263     cls.lpfnWndProc = PopupMsgCheckProcA;
7264     cls.lpszClassName = "TestPopupClass";
7265     if(!RegisterClassA(&cls)) return FALSE;
7266
7267     cls.lpfnWndProc = ParentMsgCheckProcA;
7268     cls.lpszClassName = "TestParentClass";
7269     if(!RegisterClassA(&cls)) return FALSE;
7270
7271     cls.lpfnWndProc = DefWindowProcA;
7272     cls.lpszClassName = "SimpleWindowClass";
7273     if(!RegisterClassA(&cls)) return FALSE;
7274
7275     cls.lpfnWndProc = PaintLoopProcA;
7276     cls.lpszClassName = "PaintLoopWindowClass";
7277     if(!RegisterClassA(&cls)) return FALSE;
7278
7279     cls.style = CS_NOCLOSE;
7280     cls.lpszClassName = "NoCloseWindowClass";
7281     if(!RegisterClassA(&cls)) return FALSE;
7282
7283     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7284     cls.style = 0;
7285     cls.hInstance = GetModuleHandleA(0);
7286     cls.hbrBackground = 0;
7287     cls.lpfnWndProc = TestDlgProcA;
7288     cls.lpszClassName = "TestDialogClass";
7289     if(!RegisterClassA(&cls)) return FALSE;
7290
7291     clsW.style = 0;
7292     clsW.lpfnWndProc = MsgCheckProcW;
7293     clsW.cbClsExtra = 0;
7294     clsW.cbWndExtra = 0;
7295     clsW.hInstance = GetModuleHandleW(0);
7296     clsW.hIcon = 0;
7297     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7298     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7299     clsW.lpszMenuName = NULL;
7300     clsW.lpszClassName = testWindowClassW;
7301     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7302
7303     return TRUE;
7304 }
7305
7306 static BOOL is_our_logged_class(HWND hwnd)
7307 {
7308     char buf[256];
7309
7310     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7311     {
7312         if (!lstrcmpiA(buf, "TestWindowClass") ||
7313             !lstrcmpiA(buf, "ShowWindowClass") ||
7314             !lstrcmpiA(buf, "TestParentClass") ||
7315             !lstrcmpiA(buf, "TestPopupClass") ||
7316             !lstrcmpiA(buf, "SimpleWindowClass") ||
7317             !lstrcmpiA(buf, "TestDialogClass") ||
7318             !lstrcmpiA(buf, "MDI_frame_class") ||
7319             !lstrcmpiA(buf, "MDI_client_class") ||
7320             !lstrcmpiA(buf, "MDI_child_class") ||
7321             !lstrcmpiA(buf, "my_button_class") ||
7322             !lstrcmpiA(buf, "my_edit_class") ||
7323             !lstrcmpiA(buf, "static") ||
7324             !lstrcmpiA(buf, "ListBox") ||
7325             !lstrcmpiA(buf, "ComboBox") ||
7326             !lstrcmpiA(buf, "MyDialogClass") ||
7327             !lstrcmpiA(buf, "#32770") ||
7328             !lstrcmpiA(buf, "#32768"))
7329         return TRUE;
7330     }
7331     return FALSE;
7332 }
7333
7334 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7335
7336     HWND hwnd;
7337
7338     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7339
7340     if (nCode == HCBT_CLICKSKIPPED)
7341     {
7342         /* ignore this event, XP sends it a lot when switching focus between windows */
7343         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7344     }
7345
7346     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7347     {
7348         struct recvd_message msg;
7349
7350         msg.hwnd = 0;
7351         msg.message = nCode;
7352         msg.flags = hook|wparam|lparam;
7353         msg.wParam = wParam;
7354         msg.lParam = lParam;
7355         msg.descr = "CBT";
7356         add_message(&msg);
7357
7358         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7359     }
7360
7361     if (nCode == HCBT_DESTROYWND)
7362     {
7363         if (test_DestroyWindow_flag)
7364         {
7365             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7366             if (style & WS_CHILD)
7367                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7368             else if (style & WS_POPUP)
7369                 lParam = WND_POPUP_ID;
7370             else
7371                 lParam = WND_PARENT_ID;
7372         }
7373     }
7374
7375     /* Log also SetFocus(0) calls */
7376     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7377
7378     if (is_our_logged_class(hwnd))
7379     {
7380         struct recvd_message msg;
7381
7382         msg.hwnd = hwnd;
7383         msg.message = nCode;
7384         msg.flags = hook|wparam|lparam;
7385         msg.wParam = wParam;
7386         msg.lParam = lParam;
7387         msg.descr = "CBT";
7388         add_message(&msg);
7389     }
7390     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7391 }
7392
7393 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7394                                     DWORD event,
7395                                     HWND hwnd,
7396                                     LONG object_id,
7397                                     LONG child_id,
7398                                     DWORD thread_id,
7399                                     DWORD event_time)
7400 {
7401     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7402
7403     /* ignore mouse cursor events */
7404     if (object_id == OBJID_CURSOR) return;
7405
7406     if (!hwnd || is_our_logged_class(hwnd))
7407     {
7408         struct recvd_message msg;
7409
7410         msg.hwnd = hwnd;
7411         msg.message = event;
7412         msg.flags = winevent_hook|wparam|lparam;
7413         msg.wParam = object_id;
7414         msg.lParam = child_id;
7415         msg.descr = "WEH";
7416         add_message(&msg);
7417     }
7418 }
7419
7420 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7421 static const WCHAR wszAnsi[] = {'U',0};
7422
7423 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7424 {
7425     switch (uMsg)
7426     {
7427     case CB_FINDSTRINGEXACT:
7428         trace("String: %p\n", (LPCWSTR)lParam);
7429         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7430             return 1;
7431         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7432             return 0;
7433         return -1;
7434     }
7435     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7436 }
7437
7438 static const struct message WmGetTextLengthAfromW[] = {
7439     { WM_GETTEXTLENGTH, sent },
7440     { WM_GETTEXT, sent|optional },
7441     { 0 }
7442 };
7443
7444 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7445
7446 /* dummy window proc for WM_GETTEXTLENGTH test */
7447 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7448 {
7449     switch(msg)
7450     {
7451     case WM_GETTEXTLENGTH:
7452         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7453     case WM_GETTEXT:
7454         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7455         return lstrlenW( (LPWSTR)lp );
7456     default:
7457         return DefWindowProcW( hwnd, msg, wp, lp );
7458     }
7459 }
7460
7461 static void test_message_conversion(void)
7462 {
7463     static const WCHAR wszMsgConversionClass[] =
7464         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7465     WNDCLASSW cls;
7466     LRESULT lRes;
7467     HWND hwnd;
7468     WNDPROC wndproc, newproc;
7469     BOOL ret;
7470
7471     cls.style = 0;
7472     cls.lpfnWndProc = MsgConversionProcW;
7473     cls.cbClsExtra = 0;
7474     cls.cbWndExtra = 0;
7475     cls.hInstance = GetModuleHandleW(NULL);
7476     cls.hIcon = NULL;
7477     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7478     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7479     cls.lpszMenuName = NULL;
7480     cls.lpszClassName = wszMsgConversionClass;
7481     /* this call will fail on Win9x, but that doesn't matter as this test is
7482      * meaningless on those platforms */
7483     if(!RegisterClassW(&cls)) return;
7484
7485     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7486                            100, 100, 200, 200, 0, 0, 0, NULL);
7487     ok(hwnd != NULL, "Window creation failed\n");
7488
7489     /* {W, A} -> A */
7490
7491     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7492     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7493     ok(lRes == 0, "String should have been converted\n");
7494     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7495     ok(lRes == 1, "String shouldn't have been converted\n");
7496
7497     /* {W, A} -> W */
7498
7499     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7500     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7501     ok(lRes == 1, "String shouldn't have been converted\n");
7502     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7503     ok(lRes == 1, "String shouldn't have been converted\n");
7504
7505     /* Synchronous messages */
7506
7507     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7508     ok(lRes == 0, "String should have been converted\n");
7509     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7510     ok(lRes == 1, "String shouldn't have been converted\n");
7511
7512     /* Asynchronous messages */
7513
7514     SetLastError(0);
7515     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7516     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7517         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7518     SetLastError(0);
7519     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7520     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7521         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7522     SetLastError(0);
7523     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7524     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7525         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7526     SetLastError(0);
7527     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7528     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7529         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7530     SetLastError(0);
7531     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7532     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7533         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7534     SetLastError(0);
7535     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7536     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7537         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7538     SetLastError(0);
7539     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7540     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7541         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7542     SetLastError(0);
7543     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7544     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7545         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7546
7547     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7548
7549     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7550                           WS_OVERLAPPEDWINDOW,
7551                           100, 100, 200, 200, 0, 0, 0, NULL);
7552     assert(hwnd);
7553     flush_sequence();
7554     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7555     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7556     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7557         "got bad length %ld\n", lRes );
7558
7559     flush_sequence();
7560     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7561                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7562     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7563     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7564         "got bad length %ld\n", lRes );
7565
7566     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7567     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7568     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7569     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7570                                      NULL, 0, NULL, NULL ) ||
7571         broken(lRes == lstrlenW(dummy_window_text) + 37),
7572         "got bad length %ld\n", lRes );
7573
7574     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7575     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7576     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7577                                      NULL, 0, NULL, NULL ) ||
7578         broken(lRes == lstrlenW(dummy_window_text) + 37),
7579         "got bad length %ld\n", lRes );
7580
7581     ret = DestroyWindow(hwnd);
7582     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7583 }
7584
7585 struct timer_info
7586 {
7587     HWND hWnd;
7588     HANDLE handles[2];
7589     DWORD id;
7590 };
7591
7592 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7593 {
7594 }
7595
7596 #define TIMER_ID  0x19
7597
7598 static DWORD WINAPI timer_thread_proc(LPVOID x)
7599 {
7600     struct timer_info *info = x;
7601     DWORD r;
7602
7603     r = KillTimer(info->hWnd, 0x19);
7604     ok(r,"KillTimer failed in thread\n");
7605     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7606     ok(r,"SetTimer failed in thread\n");
7607     ok(r==TIMER_ID,"SetTimer id different\n");
7608     r = SetEvent(info->handles[0]);
7609     ok(r,"SetEvent failed in thread\n");
7610     return 0;
7611 }
7612
7613 static void test_timers(void)
7614 {
7615     struct timer_info info;
7616     DWORD id;
7617
7618     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7619        WS_OVERLAPPEDWINDOW ,
7620        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7621        NULL, NULL, 0);
7622
7623     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7624     ok(info.id, "SetTimer failed\n");
7625     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7626     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7627     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7628
7629     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7630
7631     WaitForSingleObject(info.handles[1], INFINITE);
7632
7633     CloseHandle(info.handles[0]);
7634     CloseHandle(info.handles[1]);
7635
7636     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7637
7638     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7639 }
7640
7641 static int count = 0;
7642 static VOID CALLBACK callback_count(
7643     HWND hwnd,
7644     UINT uMsg,
7645     UINT_PTR idEvent,
7646     DWORD dwTime
7647 )
7648 {
7649     count++;
7650 }
7651
7652 static void test_timers_no_wnd(void)
7653 {
7654     UINT_PTR id, id2;
7655     MSG msg;
7656
7657     count = 0;
7658     id = SetTimer(NULL, 0, 100, callback_count);
7659     ok(id != 0, "did not get id from SetTimer.\n");
7660     id2 = SetTimer(NULL, id, 200, callback_count);
7661     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7662     Sleep(150);
7663     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7664     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7665     Sleep(150);
7666     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7667     ok(count == 1, "did not get one count as expected (%i).\n", count);
7668     KillTimer(NULL, id);
7669     Sleep(250);
7670     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7671     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7672 }
7673
7674 /* Various win events with arbitrary parameters */
7675 static const struct message WmWinEventsSeq[] = {
7676     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7677     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7678     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7679     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7680     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7681     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7682     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7683     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7684     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7685     /* our win event hook ignores OBJID_CURSOR events */
7686     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7687     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7688     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7689     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7690     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7691     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7692     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7693     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7694     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7695     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7696     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7697     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7698     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7699     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7700     { 0 }
7701 };
7702 static const struct message WmWinEventCaretSeq[] = {
7703     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7704     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7705     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7706     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7707     { 0 }
7708 };
7709 static const struct message WmWinEventCaretSeq_2[] = {
7710     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7711     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7712     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7713     { 0 }
7714 };
7715 static const struct message WmWinEventAlertSeq[] = {
7716     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7717     { 0 }
7718 };
7719 static const struct message WmWinEventAlertSeq_2[] = {
7720     /* create window in the thread proc */
7721     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7722     /* our test event */
7723     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7724     { 0 }
7725 };
7726 static const struct message WmGlobalHookSeq_1[] = {
7727     /* create window in the thread proc */
7728     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7729     /* our test events */
7730     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7731     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7732     { 0 }
7733 };
7734 static const struct message WmGlobalHookSeq_2[] = {
7735     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7736     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7737     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7738     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7739     { 0 }
7740 };
7741
7742 static const struct message WmMouseLLHookSeq[] = {
7743     { WM_MOUSEMOVE, hook },
7744     { WM_LBUTTONUP, hook },
7745     { WM_MOUSEMOVE, hook },
7746     { 0 }
7747 };
7748
7749 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7750                                          DWORD event,
7751                                          HWND hwnd,
7752                                          LONG object_id,
7753                                          LONG child_id,
7754                                          DWORD thread_id,
7755                                          DWORD event_time)
7756 {
7757     char buf[256];
7758
7759     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7760     {
7761         if (!lstrcmpiA(buf, "TestWindowClass") ||
7762             !lstrcmpiA(buf, "static"))
7763         {
7764             struct recvd_message msg;
7765
7766             msg.hwnd = hwnd;
7767             msg.message = event;
7768             msg.flags = winevent_hook|wparam|lparam;
7769             msg.wParam = object_id;
7770             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7771             msg.descr = "WEH_2";
7772             add_message(&msg);
7773         }
7774     }
7775 }
7776
7777 static HHOOK hCBT_global_hook;
7778 static DWORD cbt_global_hook_thread_id;
7779
7780 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7781
7782     HWND hwnd;
7783     char buf[256];
7784
7785     if (nCode == HCBT_SYSCOMMAND)
7786     {
7787         struct recvd_message msg;
7788
7789         msg.hwnd = 0;
7790         msg.message = nCode;
7791         msg.flags = hook|wparam|lparam;
7792         msg.wParam = wParam;
7793         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7794         msg.descr = "CBT_2";
7795         add_message(&msg);
7796
7797         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7798     }
7799     /* WH_MOUSE_LL hook */
7800     if (nCode == HC_ACTION)
7801     {
7802         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7803
7804         /* we can't test for real mouse events */
7805         if (mhll->flags & LLMHF_INJECTED)
7806         {
7807             struct recvd_message msg;
7808
7809             memset (&msg, 0, sizeof (msg));
7810             msg.message = wParam;
7811             msg.flags = hook;
7812             msg.descr = "CBT_2";
7813             add_message(&msg);
7814         }
7815         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7816     }
7817
7818     /* Log also SetFocus(0) calls */
7819     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7820
7821     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7822     {
7823         if (!lstrcmpiA(buf, "TestWindowClass") ||
7824             !lstrcmpiA(buf, "static"))
7825         {
7826             struct recvd_message msg;
7827
7828             msg.hwnd = hwnd;
7829             msg.message = nCode;
7830             msg.flags = hook|wparam|lparam;
7831             msg.wParam = wParam;
7832             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7833             msg.descr = "CBT_2";
7834             add_message(&msg);
7835         }
7836     }
7837     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7838 }
7839
7840 static DWORD WINAPI win_event_global_thread_proc(void *param)
7841 {
7842     HWND hwnd;
7843     MSG msg;
7844     HANDLE hevent = *(HANDLE *)param;
7845
7846     assert(pNotifyWinEvent);
7847
7848     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7849     assert(hwnd);
7850     trace("created thread window %p\n", hwnd);
7851
7852     *(HWND *)param = hwnd;
7853
7854     flush_sequence();
7855     /* this event should be received only by our new hook proc,
7856      * an old one does not expect an event from another thread.
7857      */
7858     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7859     SetEvent(hevent);
7860
7861     while (GetMessage(&msg, 0, 0, 0))
7862     {
7863         TranslateMessage(&msg);
7864         DispatchMessage(&msg);
7865     }
7866     return 0;
7867 }
7868
7869 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7870 {
7871     HWND hwnd;
7872     MSG msg;
7873     HANDLE hevent = *(HANDLE *)param;
7874
7875     flush_sequence();
7876     /* these events should be received only by our new hook proc,
7877      * an old one does not expect an event from another thread.
7878      */
7879
7880     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7881     assert(hwnd);
7882     trace("created thread window %p\n", hwnd);
7883
7884     *(HWND *)param = hwnd;
7885
7886     /* Windows doesn't like when a thread plays games with the focus,
7887        that leads to all kinds of misbehaviours and failures to activate
7888        a window. So, better keep next lines commented out.
7889     SetFocus(0);
7890     SetFocus(hwnd);*/
7891
7892     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7893     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7894
7895     SetEvent(hevent);
7896
7897     while (GetMessage(&msg, 0, 0, 0))
7898     {
7899         TranslateMessage(&msg);
7900         DispatchMessage(&msg);
7901     }
7902     return 0;
7903 }
7904
7905 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7906 {
7907     HWND hwnd;
7908     MSG msg;
7909     HANDLE hevent = *(HANDLE *)param;
7910
7911     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7912     assert(hwnd);
7913     trace("created thread window %p\n", hwnd);
7914
7915     *(HWND *)param = hwnd;
7916
7917     flush_sequence();
7918
7919     /* Windows doesn't like when a thread plays games with the focus,
7920      * that leads to all kinds of misbehaviours and failures to activate
7921      * a window. So, better don't generate a mouse click message below.
7922      */
7923     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7924     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7925     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7926
7927     SetEvent(hevent);
7928     while (GetMessage(&msg, 0, 0, 0))
7929     {
7930         TranslateMessage(&msg);
7931         DispatchMessage(&msg);
7932     }
7933     return 0;
7934 }
7935
7936 static void test_winevents(void)
7937 {
7938     BOOL ret;
7939     MSG msg;
7940     HWND hwnd, hwnd2;
7941     UINT i;
7942     HANDLE hthread, hevent;
7943     DWORD tid;
7944     HWINEVENTHOOK hhook;
7945     const struct message *events = WmWinEventsSeq;
7946
7947     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7948                            WS_OVERLAPPEDWINDOW,
7949                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7950                            NULL, NULL, 0);
7951     assert(hwnd);
7952
7953     /****** start of global hook test *************/
7954     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7955     if (!hCBT_global_hook)
7956     {
7957         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7958         skip( "cannot set global hook\n" );
7959         return;
7960     }
7961
7962     hevent = CreateEventA(NULL, 0, 0, NULL);
7963     assert(hevent);
7964     hwnd2 = hevent;
7965
7966     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7967     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7968
7969     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7970
7971     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7972
7973     flush_sequence();
7974     /* this one should be received only by old hook proc */
7975     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7976     /* this one should be received only by old hook proc */
7977     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7978
7979     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7980
7981     ret = UnhookWindowsHookEx(hCBT_global_hook);
7982     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7983
7984     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7985     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7986     CloseHandle(hthread);
7987     CloseHandle(hevent);
7988     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7989     /****** end of global hook test *************/
7990
7991     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7992     {
7993         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7994         return;
7995     }
7996
7997     flush_sequence();
7998
7999     if (0)
8000     {
8001     /* this test doesn't pass under Win9x */
8002     /* win2k ignores events with hwnd == 0 */
8003     SetLastError(0xdeadbeef);
8004     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8005     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8006        GetLastError() == 0xdeadbeef, /* Win9x */
8007        "unexpected error %d\n", GetLastError());
8008     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8009     }
8010
8011     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8012         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8013
8014     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8015
8016     /****** start of event filtering test *************/
8017     hhook = pSetWinEventHook(
8018         EVENT_OBJECT_SHOW, /* 0x8002 */
8019         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8020         GetModuleHandleA(0), win_event_global_hook_proc,
8021         GetCurrentProcessId(), 0,
8022         WINEVENT_INCONTEXT);
8023     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8024
8025     hevent = CreateEventA(NULL, 0, 0, NULL);
8026     assert(hevent);
8027     hwnd2 = hevent;
8028
8029     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8030     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8031
8032     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8033
8034     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8035
8036     flush_sequence();
8037     /* this one should be received only by old hook proc */
8038     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8039     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8040     /* this one should be received only by old hook proc */
8041     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8042
8043     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8044
8045     ret = pUnhookWinEvent(hhook);
8046     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8047
8048     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8049     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8050     CloseHandle(hthread);
8051     CloseHandle(hevent);
8052     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8053     /****** end of event filtering test *************/
8054
8055     /****** start of out of context event test *************/
8056     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8057         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8058         WINEVENT_OUTOFCONTEXT);
8059     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8060
8061     hevent = CreateEventA(NULL, 0, 0, NULL);
8062     assert(hevent);
8063     hwnd2 = hevent;
8064
8065     flush_sequence();
8066
8067     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8068     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8069
8070     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8071
8072     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8073     /* process pending winevent messages */
8074     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8075     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8076
8077     flush_sequence();
8078     /* this one should be received only by old hook proc */
8079     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8080     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8081     /* this one should be received only by old hook proc */
8082     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8083
8084     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8085     /* process pending winevent messages */
8086     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8087     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8088
8089     ret = pUnhookWinEvent(hhook);
8090     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8091
8092     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8093     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8094     CloseHandle(hthread);
8095     CloseHandle(hevent);
8096     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8097     /****** end of out of context event test *************/
8098
8099     /****** start of MOUSE_LL hook test *************/
8100     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8101     /* WH_MOUSE_LL is not supported on Win9x platforms */
8102     if (!hCBT_global_hook)
8103     {
8104         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8105         goto skip_mouse_ll_hook_test;
8106     }
8107
8108     hevent = CreateEventA(NULL, 0, 0, NULL);
8109     assert(hevent);
8110     hwnd2 = hevent;
8111
8112     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8113     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8114
8115     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8116         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8117
8118     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8119     flush_sequence();
8120
8121     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8122     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8123     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8124
8125     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8126
8127     ret = UnhookWindowsHookEx(hCBT_global_hook);
8128     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8129
8130     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8131     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8132     CloseHandle(hthread);
8133     CloseHandle(hevent);
8134     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8135     /****** end of MOUSE_LL hook test *************/
8136 skip_mouse_ll_hook_test:
8137
8138     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8139 }
8140
8141 static void test_set_hook(void)
8142 {
8143     BOOL ret;
8144     HHOOK hhook;
8145     HWINEVENTHOOK hwinevent_hook;
8146
8147     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8148     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8149     UnhookWindowsHookEx(hhook);
8150
8151     if (0)
8152     {
8153     /* this test doesn't pass under Win9x: BUG! */
8154     SetLastError(0xdeadbeef);
8155     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8156     ok(!hhook, "global hook requires hModule != 0\n");
8157     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8158     }
8159
8160     SetLastError(0xdeadbeef);
8161     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8162     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8163     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8164        GetLastError() == 0xdeadbeef, /* Win9x */
8165        "unexpected error %d\n", GetLastError());
8166
8167     SetLastError(0xdeadbeef);
8168     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8169     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8170        GetLastError() == 0xdeadbeef, /* Win9x */
8171        "unexpected error %d\n", GetLastError());
8172
8173     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8174
8175     /* even process local incontext hooks require hmodule */
8176     SetLastError(0xdeadbeef);
8177     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8178         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8179     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8180     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8181        GetLastError() == 0xdeadbeef, /* Win9x */
8182        "unexpected error %d\n", GetLastError());
8183
8184     /* even thread local incontext hooks require hmodule */
8185     SetLastError(0xdeadbeef);
8186     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8187         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8188     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8189     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8190        GetLastError() == 0xdeadbeef, /* Win9x */
8191        "unexpected error %d\n", GetLastError());
8192
8193     if (0)
8194     {
8195     /* these 3 tests don't pass under Win9x */
8196     SetLastError(0xdeadbeef);
8197     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8198         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8199     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8200     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8201
8202     SetLastError(0xdeadbeef);
8203     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8204         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8205     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8206     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8207
8208     SetLastError(0xdeadbeef);
8209     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8210         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8211     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8212     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8213     }
8214
8215     SetLastError(0xdeadbeef);
8216     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8217         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8218     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8219     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8220     ret = pUnhookWinEvent(hwinevent_hook);
8221     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8222
8223 todo_wine {
8224     /* This call succeeds under win2k SP4, but fails under Wine.
8225        Does win2k test/use passed process id? */
8226     SetLastError(0xdeadbeef);
8227     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8228         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8229     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8230     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8231     ret = pUnhookWinEvent(hwinevent_hook);
8232     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8233 }
8234
8235     SetLastError(0xdeadbeef);
8236     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8237     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8238         GetLastError() == 0xdeadbeef, /* Win9x */
8239         "unexpected error %d\n", GetLastError());
8240 }
8241
8242 static const struct message ScrollWindowPaint1[] = {
8243     { WM_PAINT, sent },
8244     { WM_ERASEBKGND, sent|beginpaint },
8245     { WM_GETTEXTLENGTH, sent|optional },
8246     { WM_PAINT, sent|optional },
8247     { WM_NCPAINT, sent|beginpaint|optional },
8248     { WM_GETTEXT, sent|beginpaint|optional },
8249     { WM_GETTEXT, sent|beginpaint|optional },
8250     { WM_GETTEXT, sent|beginpaint|optional },
8251     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8252     { WM_ERASEBKGND, sent|beginpaint|optional },
8253     { 0 }
8254 };
8255
8256 static const struct message ScrollWindowPaint2[] = {
8257     { WM_PAINT, sent },
8258     { 0 }
8259 };
8260
8261 static void test_scrollwindowex(void)
8262 {
8263     HWND hwnd, hchild;
8264     RECT rect={0,0,130,130};
8265
8266     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8267             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8268             100, 100, 200, 200, 0, 0, 0, NULL);
8269     ok (hwnd != 0, "Failed to create overlapped window\n");
8270     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8271             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8272             10, 10, 150, 150, hwnd, 0, 0, NULL);
8273     ok (hchild != 0, "Failed to create child\n");
8274     UpdateWindow(hwnd);
8275     flush_events();
8276     flush_sequence();
8277
8278     /* scroll without the child window */
8279     trace("start scroll\n");
8280     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8281             SW_ERASE|SW_INVALIDATE);
8282     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8283     trace("end scroll\n");
8284     flush_sequence();
8285     flush_events();
8286     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8287     flush_events();
8288     flush_sequence();
8289
8290     /* Now without the SW_ERASE flag */
8291     trace("start scroll\n");
8292     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8293     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8294     trace("end scroll\n");
8295     flush_sequence();
8296     flush_events();
8297     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8298     flush_events();
8299     flush_sequence();
8300
8301     /* now scroll the child window as well */
8302     trace("start scroll\n");
8303     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8304             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8305     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8306     /* windows sometimes a WM_MOVE */
8307     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8308     trace("end scroll\n");
8309     flush_sequence();
8310     flush_events();
8311     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8312     flush_events();
8313     flush_sequence();
8314
8315     /* now scroll with ScrollWindow() */
8316     trace("start scroll with ScrollWindow\n");
8317     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8318     trace("end scroll\n");
8319     flush_sequence();
8320     flush_events();
8321     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8322
8323     ok(DestroyWindow(hchild), "failed to destroy window\n");
8324     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8325     flush_sequence();
8326 }
8327
8328 static const struct message destroy_window_with_children[] = {
8329     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8330     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8331     { 0x0090, sent|optional },
8332     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8333     { 0x0090, sent|optional },
8334     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8335     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8336     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8337     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8338     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8339     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8340     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8341     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8342     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8343     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8344     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8345     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8346     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8347     { 0 }
8348 };
8349
8350 static void test_DestroyWindow(void)
8351 {
8352     BOOL ret;
8353     HWND parent, child1, child2, child3, child4, test;
8354     UINT_PTR child_id = WND_CHILD_ID + 1;
8355
8356     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8357                              100, 100, 200, 200, 0, 0, 0, NULL);
8358     assert(parent != 0);
8359     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8360                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8361     assert(child1 != 0);
8362     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8363                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8364     assert(child2 != 0);
8365     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8366                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8367     assert(child3 != 0);
8368     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8369                              0, 0, 50, 50, parent, 0, 0, NULL);
8370     assert(child4 != 0);
8371
8372     /* test owner/parent of child2 */
8373     test = GetParent(child2);
8374     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8375     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8376     if(pGetAncestor) {
8377         test = pGetAncestor(child2, GA_PARENT);
8378         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8379     }
8380     test = GetWindow(child2, GW_OWNER);
8381     ok(!test, "wrong owner %p\n", test);
8382
8383     test = SetParent(child2, parent);
8384     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8385
8386     /* test owner/parent of the parent */
8387     test = GetParent(parent);
8388     ok(!test, "wrong parent %p\n", test);
8389     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8390     if(pGetAncestor) {
8391         test = pGetAncestor(parent, GA_PARENT);
8392         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8393     }
8394     test = GetWindow(parent, GW_OWNER);
8395     ok(!test, "wrong owner %p\n", test);
8396
8397     /* test owner/parent of child1 */
8398     test = GetParent(child1);
8399     ok(test == parent, "wrong parent %p\n", test);
8400     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8401     if(pGetAncestor) {
8402         test = pGetAncestor(child1, GA_PARENT);
8403         ok(test == parent, "wrong parent %p\n", test);
8404     }
8405     test = GetWindow(child1, GW_OWNER);
8406     ok(!test, "wrong owner %p\n", test);
8407
8408     /* test owner/parent of child2 */
8409     test = GetParent(child2);
8410     ok(test == parent, "wrong parent %p\n", test);
8411     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8412     if(pGetAncestor) {
8413         test = pGetAncestor(child2, GA_PARENT);
8414         ok(test == parent, "wrong parent %p\n", test);
8415     }
8416     test = GetWindow(child2, GW_OWNER);
8417     ok(!test, "wrong owner %p\n", test);
8418
8419     /* test owner/parent of child3 */
8420     test = GetParent(child3);
8421     ok(test == child1, "wrong parent %p\n", test);
8422     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8423     if(pGetAncestor) {
8424         test = pGetAncestor(child3, GA_PARENT);
8425         ok(test == child1, "wrong parent %p\n", test);
8426     }
8427     test = GetWindow(child3, GW_OWNER);
8428     ok(!test, "wrong owner %p\n", test);
8429
8430     /* test owner/parent of child4 */
8431     test = GetParent(child4);
8432     ok(test == parent, "wrong parent %p\n", test);
8433     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8434     if(pGetAncestor) {
8435         test = pGetAncestor(child4, GA_PARENT);
8436         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8437     }
8438     test = GetWindow(child4, GW_OWNER);
8439     ok(test == parent, "wrong owner %p\n", test);
8440
8441     flush_sequence();
8442
8443     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8444            parent, child1, child2, child3, child4);
8445
8446     SetCapture(child4);
8447     test = GetCapture();
8448     ok(test == child4, "wrong capture window %p\n", test);
8449
8450     test_DestroyWindow_flag = TRUE;
8451     ret = DestroyWindow(parent);
8452     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8453     test_DestroyWindow_flag = FALSE;
8454     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8455
8456     ok(!IsWindow(parent), "parent still exists\n");
8457     ok(!IsWindow(child1), "child1 still exists\n");
8458     ok(!IsWindow(child2), "child2 still exists\n");
8459     ok(!IsWindow(child3), "child3 still exists\n");
8460     ok(!IsWindow(child4), "child4 still exists\n");
8461
8462     test = GetCapture();
8463     ok(!test, "wrong capture window %p\n", test);
8464 }
8465
8466
8467 static const struct message WmDispatchPaint[] = {
8468     { WM_NCPAINT, sent },
8469     { WM_GETTEXT, sent|defwinproc|optional },
8470     { WM_GETTEXT, sent|defwinproc|optional },
8471     { WM_ERASEBKGND, sent },
8472     { 0 }
8473 };
8474
8475 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8476 {
8477     if (message == WM_PAINT) return 0;
8478     return MsgCheckProcA( hwnd, message, wParam, lParam );
8479 }
8480
8481 static void test_DispatchMessage(void)
8482 {
8483     RECT rect;
8484     MSG msg;
8485     int count;
8486     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8487                                100, 100, 200, 200, 0, 0, 0, NULL);
8488     ShowWindow( hwnd, SW_SHOW );
8489     UpdateWindow( hwnd );
8490     flush_events();
8491     flush_sequence();
8492     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8493
8494     SetRect( &rect, -5, -5, 5, 5 );
8495     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8496     count = 0;
8497     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8498     {
8499         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8500         else
8501         {
8502             flush_sequence();
8503             DispatchMessage( &msg );
8504             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8505             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8506             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8507             if (++count > 10) break;
8508         }
8509     }
8510     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8511
8512     trace("now without DispatchMessage\n");
8513     flush_sequence();
8514     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8515     count = 0;
8516     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8517     {
8518         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8519         else
8520         {
8521             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8522             flush_sequence();
8523             /* this will send WM_NCCPAINT just like DispatchMessage does */
8524             GetUpdateRgn( hwnd, hrgn, TRUE );
8525             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8526             DeleteObject( hrgn );
8527             GetClientRect( hwnd, &rect );
8528             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8529             ok( !count, "Got multiple WM_PAINTs\n" );
8530             if (++count > 10) break;
8531         }
8532     }
8533     DestroyWindow(hwnd);
8534 }
8535
8536
8537 static const struct message WmUser[] = {
8538     { WM_USER, sent },
8539     { 0 }
8540 };
8541
8542 struct sendmsg_info
8543 {
8544     HWND  hwnd;
8545     DWORD timeout;
8546     DWORD ret;
8547 };
8548
8549 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8550 {
8551     struct sendmsg_info *info = arg;
8552     SetLastError( 0xdeadbeef );
8553     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8554     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8555                         broken(GetLastError() == 0),  /* win9x */
8556                         "unexpected error %d\n", GetLastError());
8557     return 0;
8558 }
8559
8560 static void wait_for_thread( HANDLE thread )
8561 {
8562     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8563     {
8564         MSG msg;
8565         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8566     }
8567 }
8568
8569 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8570 {
8571     if (message == WM_USER) Sleep(200);
8572     return MsgCheckProcA( hwnd, message, wParam, lParam );
8573 }
8574
8575 static void test_SendMessageTimeout(void)
8576 {
8577     HANDLE thread;
8578     struct sendmsg_info info;
8579     DWORD tid;
8580     BOOL is_win9x;
8581
8582     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8583                                100, 100, 200, 200, 0, 0, 0, NULL);
8584     flush_events();
8585     flush_sequence();
8586
8587     info.timeout = 1000;
8588     info.ret = 0xdeadbeef;
8589     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8590     wait_for_thread( thread );
8591     CloseHandle( thread );
8592     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8593     ok_sequence( WmUser, "WmUser", FALSE );
8594
8595     info.timeout = 1;
8596     info.ret = 0xdeadbeef;
8597     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8598     Sleep(100);  /* SendMessageTimeout should time out here */
8599     wait_for_thread( thread );
8600     CloseHandle( thread );
8601     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8602     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8603
8604     /* 0 means infinite timeout (but not on win9x) */
8605     info.timeout = 0;
8606     info.ret = 0xdeadbeef;
8607     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8608     Sleep(100);
8609     wait_for_thread( thread );
8610     CloseHandle( thread );
8611     is_win9x = !info.ret;
8612     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8613     else ok_sequence( WmUser, "WmUser", FALSE );
8614
8615     /* timeout is treated as signed despite the prototype (but not on win9x) */
8616     info.timeout = 0x7fffffff;
8617     info.ret = 0xdeadbeef;
8618     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8619     Sleep(100);
8620     wait_for_thread( thread );
8621     CloseHandle( thread );
8622     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8623     ok_sequence( WmUser, "WmUser", FALSE );
8624
8625     info.timeout = 0x80000000;
8626     info.ret = 0xdeadbeef;
8627     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8628     Sleep(100);
8629     wait_for_thread( thread );
8630     CloseHandle( thread );
8631     if (is_win9x)
8632     {
8633         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8634         ok_sequence( WmUser, "WmUser", FALSE );
8635     }
8636     else
8637     {
8638         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8639         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8640     }
8641
8642     /* now check for timeout during message processing */
8643     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8644     info.timeout = 100;
8645     info.ret = 0xdeadbeef;
8646     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8647     wait_for_thread( thread );
8648     CloseHandle( thread );
8649     /* we should time out but still get the message */
8650     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8651     ok_sequence( WmUser, "WmUser", FALSE );
8652
8653     DestroyWindow( info.hwnd );
8654 }
8655
8656
8657 /****************** edit message test *************************/
8658 #define ID_EDIT 0x1234
8659 static const struct message sl_edit_setfocus[] =
8660 {
8661     { HCBT_SETFOCUS, hook },
8662     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8663     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8664     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8665     { WM_SETFOCUS, sent|wparam, 0 },
8666     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8667     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8668     { WM_CTLCOLOREDIT, sent|parent },
8669     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8670     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8671     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8672     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8673     { 0 }
8674 };
8675 static const struct message ml_edit_setfocus[] =
8676 {
8677     { HCBT_SETFOCUS, hook },
8678     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8679     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8680     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8681     { WM_SETFOCUS, sent|wparam, 0 },
8682     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8683     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8684     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8685     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8686     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8687     { 0 }
8688 };
8689 static const struct message sl_edit_killfocus[] =
8690 {
8691     { HCBT_SETFOCUS, hook },
8692     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8693     { WM_KILLFOCUS, sent|wparam, 0 },
8694     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8695     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8696     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8697     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8698     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8699     { 0 }
8700 };
8701 static const struct message sl_edit_lbutton_dblclk[] =
8702 {
8703     { WM_LBUTTONDBLCLK, sent },
8704     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8705     { 0 }
8706 };
8707 static const struct message sl_edit_lbutton_down[] =
8708 {
8709     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8710     { HCBT_SETFOCUS, hook },
8711     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8712     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8713     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8714     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8715     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8716     { WM_CTLCOLOREDIT, sent|parent },
8717     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8718     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8719     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8720     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8721     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8722     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8723     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8724     { WM_CTLCOLOREDIT, sent|parent|optional },
8725     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8726     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8727     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8728     { 0 }
8729 };
8730 static const struct message ml_edit_lbutton_down[] =
8731 {
8732     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8733     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8734     { HCBT_SETFOCUS, hook },
8735     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8736     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8737     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8738     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8739     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8740     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8741     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8742     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8743     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8744     { 0 }
8745 };
8746 static const struct message sl_edit_lbutton_up[] =
8747 {
8748     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8749     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8750     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8751     { WM_CAPTURECHANGED, sent|defwinproc },
8752     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8753     { 0 }
8754 };
8755 static const struct message ml_edit_lbutton_up[] =
8756 {
8757     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8758     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8759     { WM_CAPTURECHANGED, sent|defwinproc },
8760     { 0 }
8761 };
8762
8763 static WNDPROC old_edit_proc;
8764
8765 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8766 {
8767     static long defwndproc_counter = 0;
8768     LRESULT ret;
8769     struct recvd_message msg;
8770
8771     if (ignore_message( message )) return 0;
8772
8773     msg.hwnd = hwnd;
8774     msg.message = message;
8775     msg.flags = sent|wparam|lparam;
8776     if (defwndproc_counter) msg.flags |= defwinproc;
8777     msg.wParam = wParam;
8778     msg.lParam = lParam;
8779     msg.descr = "edit";
8780     add_message(&msg);
8781
8782     defwndproc_counter++;
8783     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8784     defwndproc_counter--;
8785
8786     return ret;
8787 }
8788
8789 static void subclass_edit(void)
8790 {
8791     WNDCLASSA cls;
8792
8793     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8794
8795     old_edit_proc = cls.lpfnWndProc;
8796
8797     cls.hInstance = GetModuleHandle(0);
8798     cls.lpfnWndProc = edit_hook_proc;
8799     cls.lpszClassName = "my_edit_class";
8800     UnregisterClass(cls.lpszClassName, cls.hInstance);
8801     if (!RegisterClassA(&cls)) assert(0);
8802 }
8803
8804 static void test_edit_messages(void)
8805 {
8806     HWND hwnd, parent;
8807     DWORD dlg_code;
8808
8809     subclass_edit();
8810     log_all_parent_messages++;
8811
8812     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8813                              100, 100, 200, 200, 0, 0, 0, NULL);
8814     ok (parent != 0, "Failed to create parent window\n");
8815
8816     /* test single line edit */
8817     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8818                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8819     ok(hwnd != 0, "Failed to create edit window\n");
8820
8821     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8822     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8823
8824     ShowWindow(hwnd, SW_SHOW);
8825     UpdateWindow(hwnd);
8826     SetFocus(0);
8827     flush_sequence();
8828
8829     SetFocus(hwnd);
8830     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8831
8832     SetFocus(0);
8833     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8834
8835     SetFocus(0);
8836     ReleaseCapture();
8837     flush_sequence();
8838
8839     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8840     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8841
8842     SetFocus(0);
8843     ReleaseCapture();
8844     flush_sequence();
8845
8846     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8847     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8848
8849     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8850     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8851
8852     DestroyWindow(hwnd);
8853
8854     /* test multiline edit */
8855     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8856                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8857     ok(hwnd != 0, "Failed to create edit window\n");
8858
8859     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8860     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8861        "wrong dlg_code %08x\n", dlg_code);
8862
8863     ShowWindow(hwnd, SW_SHOW);
8864     UpdateWindow(hwnd);
8865     SetFocus(0);
8866     flush_sequence();
8867
8868     SetFocus(hwnd);
8869     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8870
8871     SetFocus(0);
8872     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8873
8874     SetFocus(0);
8875     ReleaseCapture();
8876     flush_sequence();
8877
8878     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8879     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8880
8881     SetFocus(0);
8882     ReleaseCapture();
8883     flush_sequence();
8884
8885     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8886     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8887
8888     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8889     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8890
8891     DestroyWindow(hwnd);
8892     DestroyWindow(parent);
8893
8894     log_all_parent_messages--;
8895 }
8896
8897 /**************************** End of Edit test ******************************/
8898
8899 static const struct message WmKeyDownSkippedSeq[] =
8900 {
8901     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8902     { 0 }
8903 };
8904 static const struct message WmKeyDownWasDownSkippedSeq[] =
8905 {
8906     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
8907     { 0 }
8908 };
8909 static const struct message WmKeyUpSkippedSeq[] =
8910 {
8911     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8912     { 0 }
8913 };
8914 static const struct message WmUserKeyUpSkippedSeq[] =
8915 {
8916     { WM_USER, sent },
8917     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8918     { 0 }
8919 };
8920
8921 #define EV_STOP 0
8922 #define EV_SENDMSG 1
8923 #define EV_ACK 2
8924
8925 struct peekmsg_info
8926 {
8927     HWND  hwnd;
8928     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8929 };
8930
8931 static DWORD CALLBACK send_msg_thread_2(void *param)
8932 {
8933     DWORD ret;
8934     struct peekmsg_info *info = param;
8935
8936     trace("thread: looping\n");
8937     SetEvent(info->hevent[EV_ACK]);
8938
8939     while (1)
8940     {
8941         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8942
8943         switch (ret)
8944         {
8945         case WAIT_OBJECT_0 + EV_STOP:
8946             trace("thread: exiting\n");
8947             return 0;
8948
8949         case WAIT_OBJECT_0 + EV_SENDMSG:
8950             trace("thread: sending message\n");
8951             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
8952                 "SendNotifyMessageA failed error %u\n", GetLastError());
8953             SetEvent(info->hevent[EV_ACK]);
8954             break;
8955
8956         default:
8957             trace("unexpected return: %04x\n", ret);
8958             assert(0);
8959             break;
8960         }
8961     }
8962     return 0;
8963 }
8964
8965 static void test_PeekMessage(void)
8966 {
8967     MSG msg;
8968     HANDLE hthread;
8969     DWORD tid, qstatus;
8970     UINT qs_all_input = QS_ALLINPUT;
8971     UINT qs_input = QS_INPUT;
8972     BOOL ret;
8973     struct peekmsg_info info;
8974
8975     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8976                               100, 100, 200, 200, 0, 0, 0, NULL);
8977     assert(info.hwnd);
8978     ShowWindow(info.hwnd, SW_SHOW);
8979     UpdateWindow(info.hwnd);
8980     SetFocus(info.hwnd);
8981
8982     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
8983     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8984     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8985
8986     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8987     WaitForSingleObject(info.hevent[EV_ACK], 10000);
8988
8989     flush_events();
8990     flush_sequence();
8991
8992     SetLastError(0xdeadbeef);
8993     qstatus = GetQueueStatus(qs_all_input);
8994     if (GetLastError() == ERROR_INVALID_FLAGS)
8995     {
8996         trace("QS_RAWINPUT not supported on this platform\n");
8997         qs_all_input &= ~QS_RAWINPUT;
8998         qs_input &= ~QS_RAWINPUT;
8999     }
9000     if (qstatus & QS_POSTMESSAGE)
9001     {
9002         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9003         qstatus = GetQueueStatus(qs_all_input);
9004     }
9005     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9006
9007     trace("signalling to send message\n");
9008     SetEvent(info.hevent[EV_SENDMSG]);
9009     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9010
9011     /* pass invalid QS_xxxx flags */
9012     SetLastError(0xdeadbeef);
9013     qstatus = GetQueueStatus(0xffffffff);
9014     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9015     if (!qstatus)
9016     {
9017         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9018         qstatus = GetQueueStatus(qs_all_input);
9019     }
9020     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9021     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9022        "wrong qstatus %08x\n", qstatus);
9023
9024     msg.message = 0;
9025     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9026     ok(!ret,
9027        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9028         msg.message);
9029     ok_sequence(WmUser, "WmUser", FALSE);
9030
9031     qstatus = GetQueueStatus(qs_all_input);
9032     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9033
9034     keybd_event('N', 0, 0, 0);
9035     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9036     qstatus = GetQueueStatus(qs_all_input);
9037     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9038     {
9039         skip( "queuing key events not supported\n" );
9040         goto done;
9041     }
9042     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
9043        "wrong qstatus %08x\n", qstatus);
9044
9045     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9046     qstatus = GetQueueStatus(qs_all_input);
9047     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9048        "wrong qstatus %08x\n", qstatus);
9049
9050     InvalidateRect(info.hwnd, NULL, FALSE);
9051     qstatus = GetQueueStatus(qs_all_input);
9052     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9053        "wrong qstatus %08x\n", qstatus);
9054
9055     trace("signalling to send message\n");
9056     SetEvent(info.hevent[EV_SENDMSG]);
9057     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9058
9059     qstatus = GetQueueStatus(qs_all_input);
9060     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9061        "wrong qstatus %08x\n", qstatus);
9062
9063     msg.message = 0;
9064     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9065     if (ret && msg.message == WM_CHAR)
9066     {
9067         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9068         goto done;
9069     }
9070     ok(!ret,
9071        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9072         msg.message);
9073     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9074     {
9075         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9076         goto done;
9077     }
9078     ok_sequence(WmUser, "WmUser", FALSE);
9079
9080     qstatus = GetQueueStatus(qs_all_input);
9081     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9082        "wrong qstatus %08x\n", qstatus);
9083
9084     trace("signalling to send message\n");
9085     SetEvent(info.hevent[EV_SENDMSG]);
9086     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9087
9088     qstatus = GetQueueStatus(qs_all_input);
9089     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9090        "wrong qstatus %08x\n", qstatus);
9091
9092     msg.message = 0;
9093     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9094     ok(!ret,
9095        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9096         msg.message);
9097     ok_sequence(WmUser, "WmUser", FALSE);
9098
9099     qstatus = GetQueueStatus(qs_all_input);
9100     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9101        "wrong qstatus %08x\n", qstatus);
9102
9103     msg.message = 0;
9104     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9105     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9106        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9107        ret, msg.message, msg.wParam);
9108     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9109
9110     qstatus = GetQueueStatus(qs_all_input);
9111     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9112        "wrong qstatus %08x\n", qstatus);
9113
9114     msg.message = 0;
9115     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9116     ok(!ret,
9117        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9118         msg.message);
9119     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9120
9121     qstatus = GetQueueStatus(qs_all_input);
9122     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9123        "wrong qstatus %08x\n", qstatus);
9124
9125     msg.message = 0;
9126     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9127     ok(ret && msg.message == WM_PAINT,
9128        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9129     DispatchMessageA(&msg);
9130     ok_sequence(WmPaint, "WmPaint", FALSE);
9131
9132     qstatus = GetQueueStatus(qs_all_input);
9133     ok(qstatus == MAKELONG(0, QS_KEY),
9134        "wrong qstatus %08x\n", qstatus);
9135
9136     msg.message = 0;
9137     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9138     ok(!ret,
9139        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9140         msg.message);
9141     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9142
9143     qstatus = GetQueueStatus(qs_all_input);
9144     ok(qstatus == MAKELONG(0, QS_KEY),
9145        "wrong qstatus %08x\n", qstatus);
9146
9147     trace("signalling to send message\n");
9148     SetEvent(info.hevent[EV_SENDMSG]);
9149     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9150
9151     qstatus = GetQueueStatus(qs_all_input);
9152     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9153        "wrong qstatus %08x\n", qstatus);
9154
9155     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9156
9157     qstatus = GetQueueStatus(qs_all_input);
9158     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9159        "wrong qstatus %08x\n", qstatus);
9160
9161     msg.message = 0;
9162     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9163     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9164        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9165        ret, msg.message, msg.wParam);
9166     ok_sequence(WmUser, "WmUser", FALSE);
9167
9168     qstatus = GetQueueStatus(qs_all_input);
9169     ok(qstatus == MAKELONG(0, QS_KEY),
9170        "wrong qstatus %08x\n", qstatus);
9171
9172     msg.message = 0;
9173     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9174     ok(!ret,
9175        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9176         msg.message);
9177     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9178
9179     qstatus = GetQueueStatus(qs_all_input);
9180     ok(qstatus == MAKELONG(0, QS_KEY),
9181        "wrong qstatus %08x\n", qstatus);
9182
9183     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9184
9185     qstatus = GetQueueStatus(qs_all_input);
9186     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9187        "wrong qstatus %08x\n", qstatus);
9188
9189     trace("signalling to send message\n");
9190     SetEvent(info.hevent[EV_SENDMSG]);
9191     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9192
9193     qstatus = GetQueueStatus(qs_all_input);
9194     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9195        "wrong qstatus %08x\n", qstatus);
9196
9197     msg.message = 0;
9198     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9199     ok(!ret,
9200        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9201         msg.message);
9202     ok_sequence(WmUser, "WmUser", FALSE);
9203
9204     qstatus = GetQueueStatus(qs_all_input);
9205     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9206        "wrong qstatus %08x\n", qstatus);
9207
9208     msg.message = 0;
9209     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9210         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9211     else /* workaround for a missing QS_RAWINPUT support */
9212         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9213     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9214        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9215        ret, msg.message, msg.wParam);
9216     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9217
9218     qstatus = GetQueueStatus(qs_all_input);
9219     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9220        "wrong qstatus %08x\n", qstatus);
9221
9222     msg.message = 0;
9223     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9224         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9225     else /* workaround for a missing QS_RAWINPUT support */
9226         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9227     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9228        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9229        ret, msg.message, msg.wParam);
9230     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9231
9232     qstatus = GetQueueStatus(qs_all_input);
9233     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9234        "wrong qstatus %08x\n", qstatus);
9235
9236     msg.message = 0;
9237     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9238     ok(!ret,
9239        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9240         msg.message);
9241     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9242
9243     qstatus = GetQueueStatus(qs_all_input);
9244     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9245        "wrong qstatus %08x\n", qstatus);
9246
9247     msg.message = 0;
9248     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9249     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9250        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9251        ret, msg.message, msg.wParam);
9252     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9253
9254     qstatus = GetQueueStatus(qs_all_input);
9255     ok(qstatus == 0,
9256        "wrong qstatus %08x\n", qstatus);
9257
9258     msg.message = 0;
9259     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9260     ok(!ret,
9261        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9262         msg.message);
9263     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9264
9265     qstatus = GetQueueStatus(qs_all_input);
9266     ok(qstatus == 0,
9267        "wrong qstatus %08x\n", qstatus);
9268
9269     /* test whether presence of the quit flag in the queue affects
9270      * the queue state
9271      */
9272     PostQuitMessage(0x1234abcd);
9273
9274     qstatus = GetQueueStatus(qs_all_input);
9275     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9276        "wrong qstatus %08x\n", qstatus);
9277
9278     PostMessageA(info.hwnd, WM_USER, 0, 0);
9279
9280     qstatus = GetQueueStatus(qs_all_input);
9281     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9282        "wrong qstatus %08x\n", qstatus);
9283
9284     msg.message = 0;
9285     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9286     ok(ret && msg.message == WM_USER,
9287        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9288     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9289
9290     qstatus = GetQueueStatus(qs_all_input);
9291     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9292        "wrong qstatus %08x\n", qstatus);
9293
9294     msg.message = 0;
9295     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9296     ok(ret && msg.message == WM_QUIT,
9297        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9298     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9299     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9300     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9301
9302     qstatus = GetQueueStatus(qs_all_input);
9303 todo_wine {
9304     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9305        "wrong qstatus %08x\n", qstatus);
9306 }
9307
9308     msg.message = 0;
9309     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9310     ok(!ret,
9311        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9312         msg.message);
9313     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9314
9315     qstatus = GetQueueStatus(qs_all_input);
9316     ok(qstatus == 0,
9317        "wrong qstatus %08x\n", qstatus);
9318
9319     /* some GetMessage tests */
9320
9321     keybd_event('N', 0, 0, 0);
9322     qstatus = GetQueueStatus(qs_all_input);
9323     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9324
9325     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9326     qstatus = GetQueueStatus(qs_all_input);
9327     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9328
9329     if (qstatus)
9330     {
9331         ret = GetMessageA( &msg, 0, 0, 0 );
9332         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9333            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9334            ret, msg.message, msg.wParam);
9335         qstatus = GetQueueStatus(qs_all_input);
9336         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9337     }
9338
9339     if (qstatus)
9340     {
9341         ret = GetMessageA( &msg, 0, 0, 0 );
9342         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9343            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9344            ret, msg.message, msg.wParam);
9345         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9346         qstatus = GetQueueStatus(qs_all_input);
9347         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9348     }
9349
9350     keybd_event('N', 0, 0, 0);
9351     qstatus = GetQueueStatus(qs_all_input);
9352     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9353
9354     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9355     qstatus = GetQueueStatus(qs_all_input);
9356     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9357
9358     if (qstatus & (QS_KEY << 16))
9359     {
9360         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9361         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9362            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9363            ret, msg.message, msg.wParam);
9364         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9365         qstatus = GetQueueStatus(qs_all_input);
9366         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9367     }
9368
9369     if (qstatus)
9370     {
9371         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9372         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9373            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9374            ret, msg.message, msg.wParam);
9375         qstatus = GetQueueStatus(qs_all_input);
9376         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9377     }
9378
9379     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9380     qstatus = GetQueueStatus(qs_all_input);
9381     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9382
9383     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9384     qstatus = GetQueueStatus(qs_all_input);
9385     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9386
9387     trace("signalling to send message\n");
9388     SetEvent(info.hevent[EV_SENDMSG]);
9389     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9390     qstatus = GetQueueStatus(qs_all_input);
9391     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9392        "wrong qstatus %08x\n", qstatus);
9393
9394     if (qstatus & (QS_KEY << 16))
9395     {
9396         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9397         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9398            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9399            ret, msg.message, msg.wParam);
9400         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9401         qstatus = GetQueueStatus(qs_all_input);
9402         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9403     }
9404
9405     if (qstatus)
9406     {
9407         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9408         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9409            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9410            ret, msg.message, msg.wParam);
9411         qstatus = GetQueueStatus(qs_all_input);
9412         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9413     }
9414 done:
9415     trace("signalling to exit\n");
9416     SetEvent(info.hevent[EV_STOP]);
9417
9418     WaitForSingleObject(hthread, INFINITE);
9419
9420     CloseHandle(hthread);
9421     CloseHandle(info.hevent[0]);
9422     CloseHandle(info.hevent[1]);
9423     CloseHandle(info.hevent[2]);
9424
9425     DestroyWindow(info.hwnd);
9426 }
9427
9428 static void wait_move_event(HWND hwnd, int x, int y)
9429 {
9430     MSG msg;
9431     DWORD time;
9432     BOOL  ret;
9433     int go = 0;
9434
9435     time = GetTickCount();
9436     while (GetTickCount() - time < 200 && !go) {
9437         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9438         go  = ret && msg.pt.x > x && msg.pt.y > y;
9439         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9440     }
9441 }
9442
9443 #define STEP 5
9444 static void test_PeekMessage2(void)
9445 {
9446     HWND hwnd;
9447     BOOL ret;
9448     MSG msg;
9449     UINT message;
9450     DWORD time1, time2, time3;
9451     int x1, y1, x2, y2, x3, y3;
9452     POINT pos;
9453
9454     time1 = time2 = time3 = 0;
9455     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9456
9457     /* Initialise window and make sure it is ready for events */
9458     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9459                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9460     assert(hwnd);
9461     trace("Window for test_PeekMessage2 %p\n", hwnd);
9462     ShowWindow(hwnd, SW_SHOW);
9463     UpdateWindow(hwnd);
9464     SetFocus(hwnd);
9465     GetCursorPos(&pos);
9466     SetCursorPos(100, 100);
9467     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9468     flush_events();
9469
9470     /* Do initial mousemove, wait until we can see it
9471        and then do our test peek with PM_NOREMOVE. */
9472     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9473     wait_move_event(hwnd, 100-STEP, 100-STEP);
9474
9475     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9476     if (!ret)
9477     {
9478         skip( "queuing mouse events not supported\n" );
9479         goto done;
9480     }
9481     else
9482     {
9483         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9484         message = msg.message;
9485         time1 = msg.time;
9486         x1 = msg.pt.x;
9487         y1 = msg.pt.y;
9488         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9489     }
9490
9491     /* Allow time to advance a bit, and then simulate the user moving their
9492      * mouse around. After that we peek again with PM_NOREMOVE.
9493      * Although the previous mousemove message was never removed, the
9494      * mousemove we now peek should reflect the recent mouse movements
9495      * because the input queue will merge the move events. */
9496     Sleep(100);
9497     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9498     wait_move_event(hwnd, x1, y1);
9499
9500     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9501     ok(ret, "no message available\n");
9502     if (ret) {
9503         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9504         message = msg.message;
9505         time2 = msg.time;
9506         x2 = msg.pt.x;
9507         y2 = msg.pt.y;
9508         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9509         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9510         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9511     }
9512
9513     /* Have another go, to drive the point home */
9514     Sleep(100);
9515     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9516     wait_move_event(hwnd, x2, y2);
9517
9518     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9519     ok(ret, "no message available\n");
9520     if (ret) {
9521         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9522         message = msg.message;
9523         time3 = msg.time;
9524         x3 = msg.pt.x;
9525         y3 = msg.pt.y;
9526         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9527         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9528         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9529     }
9530
9531 done:
9532     DestroyWindow(hwnd);
9533     SetCursorPos(pos.x, pos.y);
9534     flush_events();
9535 }
9536
9537 static void test_quit_message(void)
9538 {
9539     MSG msg;
9540     BOOL ret;
9541
9542     /* test using PostQuitMessage */
9543     flush_events();
9544     PostQuitMessage(0xbeef);
9545
9546     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9547     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9548     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9549     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9550
9551     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9552     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9553
9554     ret = GetMessage(&msg, NULL, 0, 0);
9555     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9556     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9557
9558     /* note: WM_QUIT message received after WM_USER message */
9559     ret = GetMessage(&msg, NULL, 0, 0);
9560     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9561     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9562     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9563
9564     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9565     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9566
9567     /* now test with PostThreadMessage - different behaviour! */
9568     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9569
9570     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9571     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9572     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9573     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9574
9575     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9576     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9577
9578     /* note: we receive the WM_QUIT message first this time */
9579     ret = GetMessage(&msg, NULL, 0, 0);
9580     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9581     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9582     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9583
9584     ret = GetMessage(&msg, NULL, 0, 0);
9585     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9586     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9587 }
9588
9589 static const struct message WmMouseHoverSeq[] = {
9590     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9591     { WM_MOUSEACTIVATE, sent|optional },
9592     { WM_TIMER, sent|optional }, /* XP sends it */
9593     { WM_SYSTIMER, sent },
9594     { WM_MOUSEHOVER, sent|wparam, 0 },
9595     { 0 }
9596 };
9597
9598 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9599 {
9600     MSG msg;
9601     DWORD start_ticks, end_ticks;
9602
9603     start_ticks = GetTickCount();
9604     /* add some deviation (50%) to cover not expected delays */
9605     start_ticks += timeout / 2;
9606
9607     do
9608     {
9609         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9610         {
9611             /* Timer proc messages are not dispatched to the window proc,
9612              * and therefore not logged.
9613              */
9614             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9615             {
9616                 struct recvd_message s_msg;
9617
9618                 s_msg.hwnd = msg.hwnd;
9619                 s_msg.message = msg.message;
9620                 s_msg.flags = sent|wparam|lparam;
9621                 s_msg.wParam = msg.wParam;
9622                 s_msg.lParam = msg.lParam;
9623                 s_msg.descr = "msg_loop";
9624                 add_message(&s_msg);
9625             }
9626             DispatchMessage(&msg);
9627         }
9628
9629         end_ticks = GetTickCount();
9630
9631         /* inject WM_MOUSEMOVE to see how it changes tracking */
9632         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9633         {
9634             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9635             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9636
9637             inject_mouse_move = FALSE;
9638         }
9639     } while (start_ticks + timeout >= end_ticks);
9640 }
9641
9642 static void test_TrackMouseEvent(void)
9643 {
9644     TRACKMOUSEEVENT tme;
9645     BOOL ret;
9646     HWND hwnd, hchild;
9647     RECT rc_parent, rc_child;
9648     UINT default_hover_time, hover_width = 0, hover_height = 0;
9649
9650 #define track_hover(track_hwnd, track_hover_time) \
9651     tme.cbSize = sizeof(tme); \
9652     tme.dwFlags = TME_HOVER; \
9653     tme.hwndTrack = track_hwnd; \
9654     tme.dwHoverTime = track_hover_time; \
9655     SetLastError(0xdeadbeef); \
9656     ret = pTrackMouseEvent(&tme); \
9657     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9658
9659 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9660     tme.cbSize = sizeof(tme); \
9661     tme.dwFlags = TME_QUERY; \
9662     tme.hwndTrack = (HWND)0xdeadbeef; \
9663     tme.dwHoverTime = 0xdeadbeef; \
9664     SetLastError(0xdeadbeef); \
9665     ret = pTrackMouseEvent(&tme); \
9666     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9667     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9668     ok(tme.dwFlags == (expected_track_flags), \
9669        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9670     ok(tme.hwndTrack == (expected_track_hwnd), \
9671        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9672     ok(tme.dwHoverTime == (expected_hover_time), \
9673        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9674
9675 #define track_hover_cancel(track_hwnd) \
9676     tme.cbSize = sizeof(tme); \
9677     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9678     tme.hwndTrack = track_hwnd; \
9679     tme.dwHoverTime = 0xdeadbeef; \
9680     SetLastError(0xdeadbeef); \
9681     ret = pTrackMouseEvent(&tme); \
9682     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9683
9684     default_hover_time = 0xdeadbeef;
9685     SetLastError(0xdeadbeef);
9686     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9687     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9688        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9689     if (!ret) default_hover_time = 400;
9690     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9691
9692     SetLastError(0xdeadbeef);
9693     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9694     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9695        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9696     if (!ret) hover_width = 4;
9697     SetLastError(0xdeadbeef);
9698     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9699     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9700        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9701     if (!ret) hover_height = 4;
9702     trace("hover rect is %u x %d\n", hover_width, hover_height);
9703
9704     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9705                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9706                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9707                           NULL, NULL, 0);
9708     assert(hwnd);
9709
9710     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9711                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9712                           50, 50, 200, 200, hwnd,
9713                           NULL, NULL, 0);
9714     assert(hchild);
9715
9716     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9717     flush_events();
9718     flush_sequence();
9719
9720     tme.cbSize = 0;
9721     tme.dwFlags = TME_QUERY;
9722     tme.hwndTrack = (HWND)0xdeadbeef;
9723     tme.dwHoverTime = 0xdeadbeef;
9724     SetLastError(0xdeadbeef);
9725     ret = pTrackMouseEvent(&tme);
9726     ok(!ret, "TrackMouseEvent should fail\n");
9727     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9728        "not expected error %u\n", GetLastError());
9729
9730     tme.cbSize = sizeof(tme);
9731     tme.dwFlags = TME_HOVER;
9732     tme.hwndTrack = (HWND)0xdeadbeef;
9733     tme.dwHoverTime = 0xdeadbeef;
9734     SetLastError(0xdeadbeef);
9735     ret = pTrackMouseEvent(&tme);
9736     ok(!ret, "TrackMouseEvent should fail\n");
9737     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9738        "not expected error %u\n", GetLastError());
9739
9740     tme.cbSize = sizeof(tme);
9741     tme.dwFlags = TME_HOVER | TME_CANCEL;
9742     tme.hwndTrack = (HWND)0xdeadbeef;
9743     tme.dwHoverTime = 0xdeadbeef;
9744     SetLastError(0xdeadbeef);
9745     ret = pTrackMouseEvent(&tme);
9746     ok(!ret, "TrackMouseEvent should fail\n");
9747     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9748        "not expected error %u\n", GetLastError());
9749
9750     GetWindowRect(hwnd, &rc_parent);
9751     GetWindowRect(hchild, &rc_child);
9752     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9753
9754     /* Process messages so that the system updates its internal current
9755      * window and hittest, otherwise TrackMouseEvent calls don't have any
9756      * effect.
9757      */
9758     flush_events();
9759     flush_sequence();
9760
9761     track_query(0, NULL, 0);
9762     track_hover(hchild, 0);
9763     track_query(0, NULL, 0);
9764
9765     flush_events();
9766     flush_sequence();
9767
9768     track_hover(hwnd, 0);
9769     tme.cbSize = sizeof(tme);
9770     tme.dwFlags = TME_QUERY;
9771     tme.hwndTrack = (HWND)0xdeadbeef;
9772     tme.dwHoverTime = 0xdeadbeef;
9773     SetLastError(0xdeadbeef);
9774     ret = pTrackMouseEvent(&tme);
9775     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
9776     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
9777     if (!tme.dwFlags)
9778     {
9779         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
9780         DestroyWindow( hwnd );
9781         return;
9782     }
9783     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
9784     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
9785     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
9786        tme.dwHoverTime, default_hover_time);
9787
9788     pump_msg_loop_timeout(default_hover_time, FALSE);
9789     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9790
9791     track_query(0, NULL, 0);
9792
9793     track_hover(hwnd, HOVER_DEFAULT);
9794     track_query(TME_HOVER, hwnd, default_hover_time);
9795
9796     Sleep(default_hover_time / 2);
9797     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9798     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9799
9800     track_query(TME_HOVER, hwnd, default_hover_time);
9801
9802     pump_msg_loop_timeout(default_hover_time, FALSE);
9803     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9804
9805     track_query(0, NULL, 0);
9806
9807     track_hover(hwnd, HOVER_DEFAULT);
9808     track_query(TME_HOVER, hwnd, default_hover_time);
9809
9810     pump_msg_loop_timeout(default_hover_time, TRUE);
9811     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9812
9813     track_query(0, NULL, 0);
9814
9815     track_hover(hwnd, HOVER_DEFAULT);
9816     track_query(TME_HOVER, hwnd, default_hover_time);
9817     track_hover_cancel(hwnd);
9818
9819     DestroyWindow(hwnd);
9820
9821 #undef track_hover
9822 #undef track_query
9823 #undef track_hover_cancel
9824 }
9825
9826
9827 static const struct message WmSetWindowRgn[] = {
9828     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9829     { WM_NCCALCSIZE, sent|wparam, 1 },
9830     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9831     { WM_GETTEXT, sent|defwinproc|optional },
9832     { WM_ERASEBKGND, sent|optional },
9833     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9834     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9835     { 0 }
9836 };
9837
9838 static const struct message WmSetWindowRgn_no_redraw[] = {
9839     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9840     { WM_NCCALCSIZE, sent|wparam, 1 },
9841     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9842     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9843     { 0 }
9844 };
9845
9846 static const struct message WmSetWindowRgn_clear[] = {
9847     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
9848     { WM_NCCALCSIZE, sent|wparam, 1 },
9849     { WM_NCPAINT, sent|optional },
9850     { WM_GETTEXT, sent|defwinproc|optional },
9851     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9852     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9853     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9854     { WM_NCPAINT, sent|optional },
9855     { WM_GETTEXT, sent|defwinproc|optional },
9856     { WM_ERASEBKGND, sent|optional },
9857     { WM_WINDOWPOSCHANGING, sent|optional },
9858     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9859     { WM_NCPAINT, sent|optional },
9860     { WM_GETTEXT, sent|defwinproc|optional },
9861     { WM_ERASEBKGND, sent|optional },
9862     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9863     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9864     { WM_NCPAINT, sent|optional },
9865     { WM_GETTEXT, sent|defwinproc|optional },
9866     { WM_ERASEBKGND, sent|optional },
9867     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9868     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9869     { 0 }
9870 };
9871
9872 static void test_SetWindowRgn(void)
9873 {
9874     HRGN hrgn;
9875     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9876                                 100, 100, 200, 200, 0, 0, 0, NULL);
9877     ok( hwnd != 0, "Failed to create overlapped window\n" );
9878
9879     ShowWindow( hwnd, SW_SHOW );
9880     UpdateWindow( hwnd );
9881     flush_events();
9882     flush_sequence();
9883
9884     trace("testing SetWindowRgn\n");
9885     hrgn = CreateRectRgn( 0, 0, 150, 150 );
9886     SetWindowRgn( hwnd, hrgn, TRUE );
9887     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9888
9889     hrgn = CreateRectRgn( 30, 30, 160, 160 );
9890     SetWindowRgn( hwnd, hrgn, FALSE );
9891     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9892
9893     hrgn = CreateRectRgn( 0, 0, 180, 180 );
9894     SetWindowRgn( hwnd, hrgn, TRUE );
9895     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9896
9897     SetWindowRgn( hwnd, 0, TRUE );
9898     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9899
9900     DestroyWindow( hwnd );
9901 }
9902
9903 /*************************** ShowWindow() test ******************************/
9904 static const struct message WmShowNormal[] = {
9905     { WM_SHOWWINDOW, sent|wparam, 1 },
9906     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9907     { HCBT_ACTIVATE, hook },
9908     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9909     { HCBT_SETFOCUS, hook },
9910     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9911     { 0 }
9912 };
9913 static const struct message WmShow[] = {
9914     { WM_SHOWWINDOW, sent|wparam, 1 },
9915     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9916     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9917     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9918     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9919     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9920     { 0 }
9921 };
9922 static const struct message WmShowNoActivate_1[] = {
9923     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9924     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9925     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|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 WmShowNoActivate_2[] = {
9931     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9932     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9933     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9934     { WM_MOVE, sent|defwinproc },
9935     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9936     { HCBT_SETFOCUS, hook|optional },
9937     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9938     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9939     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9940     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9941     { 0 }
9942 };
9943 static const struct message WmShowNA_1[] = {
9944     { WM_SHOWWINDOW, sent|wparam, 1 },
9945     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9946     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9947     { 0 }
9948 };
9949 static const struct message WmShowNA_2[] = {
9950     { WM_SHOWWINDOW, sent|wparam, 1 },
9951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9952     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9953     { 0 }
9954 };
9955 static const struct message WmRestore_1[] = {
9956     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9957     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9958     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9959     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9960     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9961     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9962     { WM_MOVE, sent|defwinproc },
9963     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9964     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9965     { 0 }
9966 };
9967 static const struct message WmRestore_2[] = {
9968     { WM_SHOWWINDOW, sent|wparam, 1 },
9969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9970     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9971     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9972     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9973     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9974     { 0 }
9975 };
9976 static const struct message WmRestore_3[] = {
9977     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9978     { WM_GETMINMAXINFO, sent },
9979     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9980     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9981     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9982     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9983     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9984     { WM_MOVE, sent|defwinproc },
9985     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9986     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9987     { 0 }
9988 };
9989 static const struct message WmRestore_4[] = {
9990     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
9991     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9992     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
9993     { WM_MOVE, sent|defwinproc|optional },
9994     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
9995     { 0 }
9996 };
9997 static const struct message WmRestore_5[] = {
9998     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
9999     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10000     { HCBT_ACTIVATE, hook|optional },
10001     { HCBT_SETFOCUS, hook|optional },
10002     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10003     { WM_MOVE, sent|defwinproc|optional },
10004     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10005     { 0 }
10006 };
10007 static const struct message WmHide_1[] = {
10008     { WM_SHOWWINDOW, sent|wparam, 0 },
10009     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10010     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10011     { HCBT_ACTIVATE, hook|optional },
10012     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10013     { 0 }
10014 };
10015 static const struct message WmHide_2[] = {
10016     { WM_SHOWWINDOW, sent|wparam, 0 },
10017     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10018     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10019     { HCBT_ACTIVATE, hook|optional },
10020     { 0 }
10021 };
10022 static const struct message WmHide_3[] = {
10023     { WM_SHOWWINDOW, sent|wparam, 0 },
10024     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10025     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10026     { HCBT_SETFOCUS, hook|optional },
10027     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10028     { 0 }
10029 };
10030 static const struct message WmShowMinimized_1[] = {
10031     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10032     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10033     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10034     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10035     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10036     { WM_MOVE, sent|defwinproc },
10037     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10038     { 0 }
10039 };
10040 static const struct message WmMinimize_1[] = {
10041     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10042     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10043     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10044     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10045     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10046     { WM_MOVE, sent|defwinproc },
10047     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10048     { 0 }
10049 };
10050 static const struct message WmMinimize_2[] = {
10051     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10052     { HCBT_SETFOCUS, hook|optional },
10053     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10054     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10055     { WM_MOVE, sent|defwinproc },
10056     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10057     { 0 }
10058 };
10059 static const struct message WmMinimize_3[] = {
10060     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10061     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10062     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10063     { WM_MOVE, sent|defwinproc },
10064     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
10065     { 0 }
10066 };
10067 static const struct message WmShowMinNoActivate[] = {
10068     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10069     { WM_WINDOWPOSCHANGING, sent },
10070     { WM_WINDOWPOSCHANGED, sent },
10071     { WM_MOVE, sent|defwinproc|optional },
10072     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MINIMIZED },
10073     { 0 }
10074 };
10075 static const struct message WmMinMax_1[] = {
10076     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10077     { 0 }
10078 };
10079 static const struct message WmMinMax_2[] = {
10080     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10081     { WM_GETMINMAXINFO, sent|optional },
10082     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10083     { HCBT_ACTIVATE, hook|optional },
10084     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10085     { HCBT_SETFOCUS, hook|optional },
10086     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10087     { WM_MOVE, sent|defwinproc|optional },
10088     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10089     { HCBT_SETFOCUS, hook|optional },
10090     { 0 }
10091 };
10092 static const struct message WmMinMax_3[] = {
10093     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10094     { HCBT_SETFOCUS, hook|optional },
10095     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10096     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10097     { WM_MOVE, sent|defwinproc|optional },
10098     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MINIMIZED },
10099     { 0 }
10100 };
10101 static const struct message WmMinMax_4[] = {
10102     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10103     { 0 }
10104 };
10105 static const struct message WmShowMaximized_1[] = {
10106     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10107     { WM_GETMINMAXINFO, sent },
10108     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10109     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10110     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10111     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10112     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10113     { WM_MOVE, sent|defwinproc },
10114     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10115     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10116     { 0 }
10117 };
10118 static const struct message WmShowMaximized_2[] = {
10119     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10120     { WM_GETMINMAXINFO, sent },
10121     { WM_WINDOWPOSCHANGING, sent|optional },
10122     { HCBT_ACTIVATE, hook|optional },
10123     { WM_WINDOWPOSCHANGED, sent|optional },
10124     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10125     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10126     { WM_WINDOWPOSCHANGING, sent|optional },
10127     { HCBT_SETFOCUS, hook|optional },
10128     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10129     { WM_MOVE, sent|defwinproc },
10130     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10131     { HCBT_SETFOCUS, hook|optional },
10132     { 0 }
10133 };
10134 static const struct message WmShowMaximized_3[] = {
10135     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10136     { WM_GETMINMAXINFO, sent },
10137     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10138     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10139     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10140     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10141     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10142     { WM_MOVE, sent|defwinproc|optional },
10143     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10144     { 0 }
10145 };
10146
10147 static void test_ShowWindow(void)
10148 {
10149     /* ShowWindow commands in random order */
10150     static const struct
10151     {
10152         INT cmd; /* ShowWindow command */
10153         LPARAM ret; /* ShowWindow return value */
10154         DWORD style; /* window style after the command */
10155         const struct message *msg; /* message sequence the command produces */
10156         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10157     } sw[] =
10158     {
10159 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10160 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10161 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10162 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10163 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10164 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10165 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10166 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10167 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10168 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10169 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10170 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10171 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10172 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10173 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10174 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10175 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10176 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10177 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10178 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10179 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10180 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10181 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10182 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10183 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10184 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10185 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10186 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10187 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10188 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10189 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10190 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10191 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10192 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10193 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10194 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10195 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10196 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10197 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10198 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10199 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10200 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE },
10201 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10202 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10203 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10204 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10205 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10206 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10207 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10208 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10209 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10210 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10211 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10212 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10213 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10214 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10215 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10216     };
10217     HWND hwnd;
10218     DWORD style;
10219     LPARAM ret;
10220     INT i;
10221
10222 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10223     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10224                           120, 120, 90, 90,
10225                           0, 0, 0, NULL);
10226     assert(hwnd);
10227
10228     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10229     ok(style == 0, "expected style 0, got %08x\n", style);
10230
10231     flush_events();
10232     flush_sequence();
10233
10234     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10235     {
10236         static const char * const sw_cmd_name[13] =
10237         {
10238             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10239             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10240             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10241             "SW_NORMALNA" /* 0xCC */
10242         };
10243         char comment[64];
10244         INT idx; /* index into the above array of names */
10245
10246         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10247
10248         style = GetWindowLong(hwnd, GWL_STYLE);
10249         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10250         ret = ShowWindow(hwnd, sw[i].cmd);
10251         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10252         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10253         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10254
10255         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10256         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10257
10258         flush_events();
10259         flush_sequence();
10260     }
10261
10262     DestroyWindow(hwnd);
10263 }
10264
10265 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10266 {
10267     struct recvd_message msg;
10268
10269     if (ignore_message( message )) return 0;
10270
10271     msg.hwnd = hwnd;
10272     msg.message = message;
10273     msg.flags = sent|wparam|lparam;
10274     msg.wParam = wParam;
10275     msg.lParam = lParam;
10276     msg.descr = "dialog";
10277     add_message(&msg);
10278
10279     /* calling DefDlgProc leads to a recursion under XP */
10280
10281     switch (message)
10282     {
10283     case WM_INITDIALOG:
10284     case WM_GETDLGCODE:
10285         return 0;
10286     }
10287     return 1;
10288 }
10289
10290 static const struct message WmDefDlgSetFocus_1[] = {
10291     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10292     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10293     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10294     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10295     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10296     { HCBT_SETFOCUS, hook },
10297     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10298     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10299     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10300     { WM_SETFOCUS, sent|wparam, 0 },
10301     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10302     { WM_CTLCOLOREDIT, sent },
10303     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10304     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10305     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10306     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10307     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10308     { 0 }
10309 };
10310 static const struct message WmDefDlgSetFocus_2[] = {
10311     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10312     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10313     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10314     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10315     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10316     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10317     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10318     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10319     { 0 }
10320 };
10321 /* Creation of a dialog */
10322 static const struct message WmCreateDialogParamSeq_1[] = {
10323     { HCBT_CREATEWND, hook },
10324     { WM_NCCREATE, sent },
10325     { WM_NCCALCSIZE, sent|wparam, 0 },
10326     { WM_CREATE, sent },
10327     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10328     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10329     { WM_MOVE, sent },
10330     { WM_SETFONT, sent },
10331     { WM_INITDIALOG, sent },
10332     { WM_CHANGEUISTATE, sent|optional },
10333     { 0 }
10334 };
10335 /* Creation of a dialog */
10336 static const struct message WmCreateDialogParamSeq_2[] = {
10337     { HCBT_CREATEWND, hook },
10338     { WM_NCCREATE, sent },
10339     { WM_NCCALCSIZE, sent|wparam, 0 },
10340     { WM_CREATE, sent },
10341     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10342     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10343     { WM_MOVE, sent },
10344     { WM_CHANGEUISTATE, sent|optional },
10345     { 0 }
10346 };
10347
10348 static void test_dialog_messages(void)
10349 {
10350     WNDCLASS cls;
10351     HWND hdlg, hedit1, hedit2, hfocus;
10352     LRESULT ret;
10353
10354 #define set_selection(hctl, start, end) \
10355     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10356     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10357
10358 #define check_selection(hctl, start, end) \
10359     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10360     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10361
10362     subclass_edit();
10363
10364     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10365                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10366                           0, 0, 100, 100, 0, 0, 0, NULL);
10367     ok(hdlg != 0, "Failed to create custom dialog window\n");
10368
10369     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10370                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10371                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10372     ok(hedit1 != 0, "Failed to create edit control\n");
10373     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10374                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10375                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10376     ok(hedit2 != 0, "Failed to create edit control\n");
10377
10378     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10379     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10380
10381     hfocus = GetFocus();
10382     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10383
10384     SetFocus(hedit2);
10385     hfocus = GetFocus();
10386     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10387
10388     check_selection(hedit1, 0, 0);
10389     check_selection(hedit2, 0, 0);
10390
10391     set_selection(hedit2, 0, -1);
10392     check_selection(hedit2, 0, 3);
10393
10394     SetFocus(0);
10395     hfocus = GetFocus();
10396     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10397
10398     flush_sequence();
10399     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10400     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10401     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10402
10403     hfocus = GetFocus();
10404     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10405
10406     check_selection(hedit1, 0, 5);
10407     check_selection(hedit2, 0, 3);
10408
10409     flush_sequence();
10410     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10411     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10412     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10413
10414     hfocus = GetFocus();
10415     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10416
10417     check_selection(hedit1, 0, 5);
10418     check_selection(hedit2, 0, 3);
10419
10420     EndDialog(hdlg, 0);
10421     DestroyWindow(hedit1);
10422     DestroyWindow(hedit2);
10423     DestroyWindow(hdlg);
10424     flush_sequence();
10425
10426 #undef set_selection
10427 #undef check_selection
10428
10429     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10430     cls.lpszClassName = "MyDialogClass";
10431     cls.hInstance = GetModuleHandle(0);
10432     /* need a cast since a dlgproc is used as a wndproc */
10433     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10434     if (!RegisterClass(&cls)) assert(0);
10435
10436     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10437     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10438     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10439     EndDialog(hdlg, 0);
10440     DestroyWindow(hdlg);
10441     flush_sequence();
10442
10443     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10444     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10445     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10446     EndDialog(hdlg, 0);
10447     DestroyWindow(hdlg);
10448     flush_sequence();
10449
10450     UnregisterClass(cls.lpszClassName, cls.hInstance);
10451 }
10452
10453 static void test_nullCallback(void)
10454 {
10455     HWND hwnd;
10456
10457     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10458                            100, 100, 200, 200, 0, 0, 0, NULL);
10459     ok (hwnd != 0, "Failed to create overlapped window\n");
10460
10461     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10462     flush_events();
10463     DestroyWindow(hwnd);
10464 }
10465
10466 /* SetActiveWindow( 0 ) hwnd visible */
10467 static const struct message SetActiveWindowSeq0[] =
10468 {
10469     { HCBT_ACTIVATE, hook|optional },
10470     { WM_NCACTIVATE, sent|wparam, 0 },
10471     { WM_GETTEXT, sent|defwinproc|optional },
10472     { WM_ACTIVATE, sent|wparam, 0 },
10473     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10474     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
10475     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10476     { WM_KILLFOCUS, sent|optional },
10477     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10478     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10479     { WM_NCACTIVATE, sent|wparam|optional, 1 },
10480     { WM_GETTEXT, sent|defwinproc|optional },
10481     { WM_ACTIVATE, sent|wparam|optional, 1 },
10482     { HCBT_SETFOCUS, hook|optional },
10483     { WM_KILLFOCUS, sent|defwinproc|optional },
10484     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10485     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
10486     { WM_IME_SETCONTEXT, sent|optional },
10487     { WM_IME_SETCONTEXT, sent|optional },
10488     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10489     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10490     { WM_SETFOCUS, sent|defwinproc|optional },
10491     { WM_GETTEXT, sent|optional },
10492     { 0 }
10493 };
10494 /* SetActiveWindow( hwnd ) hwnd visible */
10495 static const struct message SetActiveWindowSeq1[] =
10496 {
10497     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10498     { 0 }
10499 };
10500 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10501 static const struct message SetActiveWindowSeq2[] =
10502 {
10503     { HCBT_ACTIVATE, hook },
10504     { WM_NCACTIVATE, sent|wparam, 0 },
10505     { WM_GETTEXT, sent|defwinproc|optional },
10506     { WM_ACTIVATE, sent|wparam, 0 },
10507     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10508     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10509     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10510     { WM_NCPAINT, sent|optional },
10511     { WM_GETTEXT, sent|defwinproc|optional },
10512     { WM_ERASEBKGND, sent|optional },
10513     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10514     { WM_NCACTIVATE, sent|wparam, 1 },
10515     { WM_GETTEXT, sent|defwinproc|optional },
10516     { WM_ACTIVATE, sent|wparam, 1 },
10517     { HCBT_SETFOCUS, hook },
10518     { WM_KILLFOCUS, sent|defwinproc },
10519     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10520     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10521     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10522     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10523     { WM_SETFOCUS, sent|defwinproc },
10524     { WM_GETTEXT, sent|optional },
10525     { 0 }
10526 };
10527
10528 /* SetActiveWindow( hwnd ) hwnd not visible */
10529 static const struct message SetActiveWindowSeq3[] =
10530 {
10531     { HCBT_ACTIVATE, hook },
10532     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10533     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10534     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10535     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10536     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10537     { WM_ACTIVATEAPP, sent|wparam, 1 },
10538     { WM_ACTIVATEAPP, sent|wparam, 1 },
10539     { WM_NCACTIVATE, sent|wparam, 1 },
10540     { WM_ACTIVATE, sent|wparam, 1 },
10541     { HCBT_SETFOCUS, hook },
10542     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10543     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10544     { WM_SETFOCUS, sent|defwinproc },
10545     { 0 }
10546 };
10547 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10548 static const struct message SetActiveWindowSeq4[] =
10549 {
10550     { HCBT_ACTIVATE, hook },
10551     { WM_NCACTIVATE, sent|wparam, 0 },
10552     { WM_GETTEXT, sent|defwinproc|optional },
10553     { WM_ACTIVATE, sent|wparam, 0 },
10554     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10555     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10556     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10557     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10558     { WM_NCACTIVATE, sent|wparam, 1 },
10559     { WM_GETTEXT, sent|defwinproc|optional },
10560     { WM_ACTIVATE, sent|wparam, 1 },
10561     { HCBT_SETFOCUS, hook },
10562     { WM_KILLFOCUS, sent|defwinproc },
10563     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10564     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10565     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10566     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10567     { WM_SETFOCUS, sent|defwinproc },
10568     { 0 }
10569 };
10570
10571
10572 static void test_SetActiveWindow(void)
10573 {
10574     HWND hwnd, popup, ret;
10575
10576     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10577                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10578                            100, 100, 200, 200, 0, 0, 0, NULL);
10579
10580     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10581                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10582                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10583
10584     ok(hwnd != 0, "Failed to create overlapped window\n");
10585     ok(popup != 0, "Failed to create popup window\n");
10586     SetForegroundWindow( popup );
10587     flush_sequence();
10588
10589     trace("SetActiveWindow(0)\n");
10590     ret = SetActiveWindow(0);
10591     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10592     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
10593     flush_sequence();
10594
10595     trace("SetActiveWindow(hwnd), hwnd visible\n");
10596     ret = SetActiveWindow(hwnd);
10597     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10598     flush_sequence();
10599
10600     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10601     ret = SetActiveWindow(popup);
10602     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10603     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10604     flush_sequence();
10605
10606     ShowWindow(hwnd, SW_HIDE);
10607     ShowWindow(popup, SW_HIDE);
10608     flush_sequence();
10609
10610     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10611     ret = SetActiveWindow(hwnd);
10612     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
10613     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10614     flush_sequence();
10615
10616     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10617     ret = SetActiveWindow(popup);
10618     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10619     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10620     flush_sequence();
10621
10622     trace("done\n");
10623
10624     DestroyWindow(hwnd);
10625 }
10626
10627 static const struct message SetForegroundWindowSeq[] =
10628 {
10629     { WM_NCACTIVATE, sent|wparam, 0 },
10630     { WM_GETTEXT, sent|defwinproc|optional },
10631     { WM_ACTIVATE, sent|wparam, 0 },
10632     { WM_ACTIVATEAPP, sent|wparam, 0 },
10633     { WM_KILLFOCUS, sent },
10634     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10635     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10636     { 0 }
10637 };
10638
10639 static void test_SetForegroundWindow(void)
10640 {
10641     HWND hwnd;
10642
10643     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10644                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10645                            100, 100, 200, 200, 0, 0, 0, NULL);
10646     ok (hwnd != 0, "Failed to create overlapped window\n");
10647     SetForegroundWindow( hwnd );
10648     flush_sequence();
10649
10650     trace("SetForegroundWindow( 0 )\n");
10651     SetForegroundWindow( 0 );
10652     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10653     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10654     SetForegroundWindow( GetDesktopWindow() );
10655     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10656                                         "foreground top level window", FALSE);
10657     trace("done\n");
10658
10659     DestroyWindow(hwnd);
10660 }
10661
10662 static void test_dbcs_wm_char(void)
10663 {
10664     BYTE dbch[2];
10665     WCHAR wch, bad_wch;
10666     HWND hwnd, hwnd2;
10667     MSG msg;
10668     DWORD time;
10669     POINT pt;
10670     DWORD_PTR res;
10671     CPINFOEXA cpinfo;
10672     UINT i, j, k;
10673     struct message wmCharSeq[2];
10674
10675     if (!pGetCPInfoExA)
10676     {
10677         win_skip("GetCPInfoExA is not available\n");
10678         return;
10679     }
10680
10681     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10682     if (cpinfo.MaxCharSize != 2)
10683     {
10684         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10685         return;
10686     }
10687
10688     dbch[0] = dbch[1] = 0;
10689     wch = 0;
10690     bad_wch = cpinfo.UnicodeDefaultChar;
10691     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10692         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10693             for (k = 128; k <= 255; k++)
10694             {
10695                 char str[2];
10696                 WCHAR wstr[2];
10697                 str[0] = j;
10698                 str[1] = k;
10699                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10700                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10701                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10702                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10703                 {
10704                     dbch[0] = j;
10705                     dbch[1] = k;
10706                     wch = wstr[0];
10707                     break;
10708                 }
10709             }
10710
10711     if (!wch)
10712     {
10713         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10714         return;
10715     }
10716     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10717            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10718
10719     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10720                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10721     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10722                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10723     ok (hwnd != 0, "Failed to create overlapped window\n");
10724     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10725     flush_sequence();
10726
10727     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10728     wmCharSeq[0].message = WM_CHAR;
10729     wmCharSeq[0].flags = sent|wparam;
10730     wmCharSeq[0].wParam = wch;
10731
10732     /* posted message */
10733     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10734     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10735     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10736     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10737     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10738     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10739     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10740
10741     /* posted thread message */
10742     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10743     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10744     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10745     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10746     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10747     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10748     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10749
10750     /* sent message */
10751     flush_sequence();
10752     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10753     ok_sequence( WmEmptySeq, "no messages", FALSE );
10754     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10755     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10756     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10757
10758     /* sent message with timeout */
10759     flush_sequence();
10760     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10761     ok_sequence( WmEmptySeq, "no messages", FALSE );
10762     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10763     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10764     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10765
10766     /* sent message with timeout and callback */
10767     flush_sequence();
10768     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10769     ok_sequence( WmEmptySeq, "no messages", FALSE );
10770     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10771     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10772     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10773
10774     /* sent message with callback */
10775     flush_sequence();
10776     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10777     ok_sequence( WmEmptySeq, "no messages", FALSE );
10778     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10779     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10780     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10781
10782     /* direct window proc call */
10783     flush_sequence();
10784     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10785     ok_sequence( WmEmptySeq, "no messages", FALSE );
10786     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10787     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10788
10789     /* dispatch message */
10790     msg.hwnd = hwnd;
10791     msg.message = WM_CHAR;
10792     msg.wParam = dbch[0];
10793     msg.lParam = 0;
10794     DispatchMessageA( &msg );
10795     ok_sequence( WmEmptySeq, "no messages", FALSE );
10796     msg.wParam = dbch[1];
10797     DispatchMessageA( &msg );
10798     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10799
10800     /* window handle is irrelevant */
10801     flush_sequence();
10802     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10803     ok_sequence( WmEmptySeq, "no messages", FALSE );
10804     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10805     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10806     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10807
10808     /* interleaved post and send */
10809     flush_sequence();
10810     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10811     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10812     ok_sequence( WmEmptySeq, "no messages", FALSE );
10813     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10814     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10815     ok_sequence( WmEmptySeq, "no messages", FALSE );
10816     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10817     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10818     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10819     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10820     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10821     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10822     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10823
10824     /* interleaved sent message and winproc */
10825     flush_sequence();
10826     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10827     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10828     ok_sequence( WmEmptySeq, "no messages", FALSE );
10829     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10830     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10831     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10832     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10833
10834     /* interleaved winproc and dispatch */
10835     msg.hwnd = hwnd;
10836     msg.message = WM_CHAR;
10837     msg.wParam = dbch[0];
10838     msg.lParam = 0;
10839     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10840     DispatchMessageA( &msg );
10841     ok_sequence( WmEmptySeq, "no messages", FALSE );
10842     msg.wParam = dbch[1];
10843     DispatchMessageA( &msg );
10844     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10845     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10846     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10847
10848     /* interleaved sends */
10849     flush_sequence();
10850     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10851     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10852     ok_sequence( WmEmptySeq, "no messages", FALSE );
10853     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10854     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10855     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10856     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10857
10858     /* dbcs WM_CHAR */
10859     flush_sequence();
10860     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10861     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10862     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10863
10864     /* other char messages are not magic */
10865     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10866     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10867     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10868     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10869     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10870     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10871     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10872     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10873     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10874     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10875
10876     /* test retrieving messages */
10877
10878     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10879     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10880     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10881     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10882     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10883     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10884     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10885     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10886     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10887     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10888
10889     /* message filters */
10890     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10891     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10892     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10893     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10894     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10895     /* message id is filtered, hwnd is not */
10896     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10897     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10898     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10899     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10900     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10901     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10902
10903     /* mixing GetMessage and PostMessage */
10904     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10905     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10906     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10907     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10908     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10909     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10910     time = msg.time;
10911     pt = msg.pt;
10912     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
10913     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10914     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10915     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10916     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10917     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10918     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
10919     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 );
10920     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10921
10922     /* without PM_REMOVE */
10923     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10924     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10925     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10926     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10927     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10928     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10929     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10930     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10931     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10932     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10933     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10934     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10935     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10936     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10937     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10938     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10939     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10940     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10941
10942     DestroyWindow(hwnd);
10943 }
10944
10945 #define ID_LISTBOX 0x000f
10946
10947 static const struct message wm_lb_setcursel_0[] =
10948 {
10949     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
10950     { WM_CTLCOLORLISTBOX, sent|parent },
10951     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10952     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10953     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10954     { 0 }
10955 };
10956 static const struct message wm_lb_setcursel_1[] =
10957 {
10958     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
10959     { WM_CTLCOLORLISTBOX, sent|parent },
10960     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
10961     { WM_CTLCOLORLISTBOX, sent|parent },
10962     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
10963     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10964     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10965     { 0 }
10966 };
10967 static const struct message wm_lb_setcursel_2[] =
10968 {
10969     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
10970     { WM_CTLCOLORLISTBOX, sent|parent },
10971     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
10972     { WM_CTLCOLORLISTBOX, sent|parent },
10973     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
10974     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10975     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10976     { 0 }
10977 };
10978 static const struct message wm_lb_click_0[] =
10979 {
10980     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10981     { HCBT_SETFOCUS, hook },
10982     { WM_KILLFOCUS, sent|parent },
10983     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10984     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10985     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10986     { WM_SETFOCUS, sent|defwinproc },
10987
10988     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10989     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10990     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10991     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10992     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10993
10994     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10995     { WM_CTLCOLORLISTBOX, sent|parent },
10996     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10997     { WM_CTLCOLORLISTBOX, sent|parent },
10998     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10999     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11000
11001     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11002     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11003
11004     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11005     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11006     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11007     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11008     { 0 }
11009 };
11010 static const struct message wm_lb_deletestring[] =
11011 {
11012     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11013     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11014     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11015     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11016     { 0 }
11017 };
11018 static const struct message wm_lb_deletestring_reset[] =
11019 {
11020     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11021     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11022     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11023     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11024     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11025     { 0 }
11026 };
11027
11028 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11029
11030 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11031
11032 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11033 {
11034     static LONG defwndproc_counter = 0;
11035     LRESULT ret;
11036     struct recvd_message msg;
11037
11038     /* do not log painting messages */
11039     if (message != WM_PAINT &&
11040         message != WM_NCPAINT &&
11041         message != WM_SYNCPAINT &&
11042         message != WM_ERASEBKGND &&
11043         message != WM_NCHITTEST &&
11044         message != WM_GETTEXT &&
11045         !ignore_message( message ))
11046     {
11047         msg.hwnd = hwnd;
11048         msg.message = message;
11049         msg.flags = sent|wparam|lparam;
11050         if (defwndproc_counter) msg.flags |= defwinproc;
11051         msg.wParam = wp;
11052         msg.lParam = lp;
11053         msg.descr = "listbox";
11054         add_message(&msg);
11055     }
11056
11057     defwndproc_counter++;
11058     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11059     defwndproc_counter--;
11060
11061     return ret;
11062 }
11063
11064 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11065                                int caret_index, int top_index, int line)
11066 {
11067     LRESULT ret;
11068
11069     /* calling an orig proc helps to avoid unnecessary message logging */
11070     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11071     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11072     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11073     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11074     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11075     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
11076     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11077     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11078 }
11079
11080 static void test_listbox_messages(void)
11081 {
11082     HWND parent, listbox;
11083     LRESULT ret;
11084
11085     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11086                              100, 100, 200, 200, 0, 0, 0, NULL);
11087     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11088                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11089                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11090     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11091
11092     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11093
11094     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11095     ok(ret == 0, "expected 0, got %ld\n", ret);
11096     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11097     ok(ret == 1, "expected 1, got %ld\n", ret);
11098     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11099     ok(ret == 2, "expected 2, got %ld\n", ret);
11100
11101     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11102
11103     flush_sequence();
11104
11105     log_all_parent_messages++;
11106
11107     trace("selecting item 0\n");
11108     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11109     ok(ret == 0, "expected 0, got %ld\n", ret);
11110     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11111     check_lb_state(listbox, 3, 0, 0, 0);
11112     flush_sequence();
11113
11114     trace("selecting item 1\n");
11115     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11116     ok(ret == 1, "expected 1, got %ld\n", ret);
11117     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11118     check_lb_state(listbox, 3, 1, 1, 0);
11119
11120     trace("selecting item 2\n");
11121     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11122     ok(ret == 2, "expected 2, got %ld\n", ret);
11123     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11124     check_lb_state(listbox, 3, 2, 2, 0);
11125
11126     trace("clicking on item 0\n");
11127     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11128     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11129     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11130     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11131     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11132     check_lb_state(listbox, 3, 0, 0, 0);
11133     flush_sequence();
11134
11135     trace("deleting item 0\n");
11136     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11137     ok(ret == 2, "expected 2, got %ld\n", ret);
11138     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11139     check_lb_state(listbox, 2, -1, 0, 0);
11140     flush_sequence();
11141
11142     trace("deleting item 0\n");
11143     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11144     ok(ret == 1, "expected 1, got %ld\n", ret);
11145     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11146     check_lb_state(listbox, 1, -1, 0, 0);
11147     flush_sequence();
11148
11149     trace("deleting item 0\n");
11150     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11151     ok(ret == 0, "expected 0, got %ld\n", ret);
11152     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11153     check_lb_state(listbox, 0, -1, 0, 0);
11154     flush_sequence();
11155
11156     trace("deleting item 0\n");
11157     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11158     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11159     check_lb_state(listbox, 0, -1, 0, 0);
11160     flush_sequence();
11161
11162     log_all_parent_messages--;
11163
11164     DestroyWindow(listbox);
11165     DestroyWindow(parent);
11166 }
11167
11168 /*************************** Menu test ******************************/
11169 static const struct message wm_popup_menu_1[] =
11170 {
11171     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11172     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11173     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11174     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11175     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11176     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11177     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11178     { WM_INITMENU, sent|lparam, 0, 0 },
11179     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11180     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11181     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11182     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11183     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11184     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11185     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11186     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11187     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11188     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11189     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11190     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11191     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11192     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11193     { 0 }
11194 };
11195 static const struct message wm_popup_menu_2[] =
11196 {
11197     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11198     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11199     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11200     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11201     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11202     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11203     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11204     { WM_INITMENU, sent|lparam, 0, 0 },
11205     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11206     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11207     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11208     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11209     { HCBT_CREATEWND, hook },
11210     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11211                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11212     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11213     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11214     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11215     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11216     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11217     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11218     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11219     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11220     { HCBT_DESTROYWND, hook },
11221     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11222     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11223     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11224     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11225     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11226     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11227     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11228     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11229     { 0 }
11230 };
11231 static const struct message wm_popup_menu_3[] =
11232 {
11233     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11234     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11235     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11236     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11237     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11238     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11239     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11240     { WM_INITMENU, sent|lparam, 0, 0 },
11241     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11242     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11243     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11244     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11245     { HCBT_CREATEWND, hook },
11246     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11247                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11248     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11249     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11250     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11251     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11252     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11253     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11254     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11255     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11256     { HCBT_DESTROYWND, hook },
11257     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11258     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11259     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11260     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11261     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11262     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11263     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11264     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11265     { 0 }
11266 };
11267
11268 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11269 {
11270     if (message == WM_ENTERIDLE ||
11271         message == WM_INITMENU ||
11272         message == WM_INITMENUPOPUP ||
11273         message == WM_MENUSELECT ||
11274         message == WM_PARENTNOTIFY ||
11275         message == WM_ENTERMENULOOP ||
11276         message == WM_EXITMENULOOP ||
11277         message == WM_UNINITMENUPOPUP ||
11278         message == WM_KEYDOWN ||
11279         message == WM_KEYUP ||
11280         message == WM_CHAR ||
11281         message == WM_SYSKEYDOWN ||
11282         message == WM_SYSKEYUP ||
11283         message == WM_SYSCHAR ||
11284         message == WM_COMMAND ||
11285         message == WM_MENUCOMMAND)
11286     {
11287         struct recvd_message msg;
11288
11289         msg.hwnd = hwnd;
11290         msg.message = message;
11291         msg.flags = sent|wparam|lparam;
11292         msg.wParam = wp;
11293         msg.lParam = lp;
11294         msg.descr = "parent_menu_proc";
11295         add_message(&msg);
11296     }
11297
11298     return DefWindowProcA(hwnd, message, wp, lp);
11299 }
11300
11301 static void set_menu_style(HMENU hmenu, DWORD style)
11302 {
11303     MENUINFO mi;
11304     BOOL ret;
11305
11306     mi.cbSize = sizeof(mi);
11307     mi.fMask = MIM_STYLE;
11308     mi.dwStyle = style;
11309     SetLastError(0xdeadbeef);
11310     ret = pSetMenuInfo(hmenu, &mi);
11311     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11312 }
11313
11314 static DWORD get_menu_style(HMENU hmenu)
11315 {
11316     MENUINFO mi;
11317     BOOL ret;
11318
11319     mi.cbSize = sizeof(mi);
11320     mi.fMask = MIM_STYLE;
11321     mi.dwStyle = 0;
11322     SetLastError(0xdeadbeef);
11323     ret = pGetMenuInfo(hmenu, &mi);
11324     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11325
11326     return mi.dwStyle;
11327 }
11328
11329 static void test_menu_messages(void)
11330 {
11331     MSG msg;
11332     WNDCLASSA cls;
11333     HMENU hmenu, hmenu_popup;
11334     HWND hwnd;
11335     DWORD style;
11336
11337     if (!pGetMenuInfo || !pSetMenuInfo)
11338     {
11339         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11340         return;
11341     }
11342     cls.style = 0;
11343     cls.lpfnWndProc = parent_menu_proc;
11344     cls.cbClsExtra = 0;
11345     cls.cbWndExtra = 0;
11346     cls.hInstance = GetModuleHandleA(0);
11347     cls.hIcon = 0;
11348     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11349     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11350     cls.lpszMenuName = NULL;
11351     cls.lpszClassName = "TestMenuClass";
11352     UnregisterClass(cls.lpszClassName, cls.hInstance);
11353     if (!RegisterClassA(&cls)) assert(0);
11354
11355     SetLastError(0xdeadbeef);
11356     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11357                            100, 100, 200, 200, 0, 0, 0, NULL);
11358     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11359
11360     SetLastError(0xdeadbeef);
11361     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11362     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11363
11364     SetMenu(hwnd, hmenu);
11365     SetForegroundWindow( hwnd );
11366
11367     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11368     style = get_menu_style(hmenu);
11369     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11370
11371     hmenu_popup = GetSubMenu(hmenu, 0);
11372     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11373     style = get_menu_style(hmenu_popup);
11374     ok(style == 0, "expected 0, got %u\n", style);
11375
11376     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11377     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11378     style = get_menu_style(hmenu_popup);
11379     ok(style == 0, "expected 0, got %u\n", style);
11380
11381     /* Alt+E, Enter */
11382     trace("testing a popup menu command\n");
11383     flush_sequence();
11384     keybd_event(VK_MENU, 0, 0, 0);
11385     keybd_event('E', 0, 0, 0);
11386     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11387     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11388     keybd_event(VK_RETURN, 0, 0, 0);
11389     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11390     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11391     {
11392         TranslateMessage(&msg);
11393         DispatchMessage(&msg);
11394     }
11395     if (!sequence_cnt)  /* we didn't get any message */
11396     {
11397         skip( "queuing key events not supported\n" );
11398         goto done;
11399     }
11400     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
11401     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
11402     {
11403         win_skip( "menu tracking through VK_MENU not supported\n" );
11404         goto done;
11405     }
11406     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11407
11408     /* Alt+F, Right, Enter */
11409     trace("testing submenu of a popup menu command\n");
11410     flush_sequence();
11411     keybd_event(VK_MENU, 0, 0, 0);
11412     keybd_event('F', 0, 0, 0);
11413     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11414     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11415     keybd_event(VK_RIGHT, 0, 0, 0);
11416     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11417     keybd_event(VK_RETURN, 0, 0, 0);
11418     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11419     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11420     {
11421         TranslateMessage(&msg);
11422         DispatchMessage(&msg);
11423     }
11424     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11425
11426     set_menu_style(hmenu, 0);
11427     style = get_menu_style(hmenu);
11428     ok(style == 0, "expected 0, got %u\n", style);
11429
11430     hmenu_popup = GetSubMenu(hmenu, 0);
11431     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11432     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11433     style = get_menu_style(hmenu_popup);
11434     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11435
11436     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11437     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11438     style = get_menu_style(hmenu_popup);
11439     ok(style == 0, "expected 0, got %u\n", style);
11440
11441     /* Alt+F, Right, Enter */
11442     trace("testing submenu of a popup menu command\n");
11443     flush_sequence();
11444     keybd_event(VK_MENU, 0, 0, 0);
11445     keybd_event('F', 0, 0, 0);
11446     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11447     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11448     keybd_event(VK_RIGHT, 0, 0, 0);
11449     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11450     keybd_event(VK_RETURN, 0, 0, 0);
11451     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11452     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11453     {
11454         TranslateMessage(&msg);
11455         DispatchMessage(&msg);
11456     }
11457     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11458
11459 done:
11460     DestroyWindow(hwnd);
11461     DestroyMenu(hmenu);
11462 }
11463
11464
11465 static void test_paintingloop(void)
11466 {
11467     HWND hwnd;
11468
11469     paint_loop_done = 0;
11470     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11471                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11472                                 100, 100, 100, 100, 0, 0, 0, NULL );
11473     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11474     ShowWindow(hwnd,SW_NORMAL);
11475     SetFocus(hwnd);
11476
11477     while (!paint_loop_done)
11478     {
11479         MSG msg;
11480         if (PeekMessageA(&msg, 0, 0, 0, 1))
11481         {
11482             TranslateMessage(&msg);
11483             DispatchMessage(&msg);
11484         }
11485     }
11486     DestroyWindow(hwnd);
11487 }
11488
11489 static void test_defwinproc(void)
11490 {
11491     HWND hwnd;
11492     MSG msg;
11493     int gotwmquit = FALSE;
11494     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
11495     assert(hwnd);
11496     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
11497     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
11498         if( msg.message == WM_QUIT) gotwmquit = TRUE;
11499         DispatchMessageA( &msg );
11500     }
11501     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
11502     DestroyWindow( hwnd);
11503 }
11504
11505 START_TEST(msg)
11506 {
11507     BOOL ret;
11508     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11509
11510     init_procs();
11511
11512     if (!RegisterWindowClasses()) assert(0);
11513
11514     if (pSetWinEventHook)
11515     {
11516         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11517                                        GetModuleHandleA(0), win_event_proc,
11518                                        0, GetCurrentThreadId(),
11519                                        WINEVENT_INCONTEXT);
11520         if (pIsWinEventHookInstalled && hEvent_hook)
11521         {
11522             UINT event;
11523             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11524                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11525         }
11526     }
11527     if (!hEvent_hook) win_skip( "no win event hook support\n" );
11528
11529     cbt_hook_thread_id = GetCurrentThreadId();
11530     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11531     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
11532
11533     test_winevents();
11534
11535     /* Fix message sequences before removing 4 lines below */
11536 #if 1
11537     if (pUnhookWinEvent && hEvent_hook)
11538     {
11539         ret = pUnhookWinEvent(hEvent_hook);
11540         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11541         pUnhookWinEvent = 0;
11542     }
11543     hEvent_hook = 0;
11544 #endif
11545
11546     test_ShowWindow();
11547     test_PeekMessage();
11548     test_PeekMessage2();
11549     test_scrollwindowex();
11550     test_messages();
11551     test_setwindowpos();
11552     test_showwindow();
11553     invisible_parent_tests();
11554     test_mdi_messages();
11555     test_button_messages();
11556     test_static_messages();
11557     test_listbox_messages();
11558     test_combobox_messages();
11559     test_wmime_keydown_message();
11560     test_paint_messages();
11561     test_interthread_messages();
11562     test_message_conversion();
11563     test_accelerators();
11564     test_timers();
11565     test_timers_no_wnd();
11566     if (hCBT_hook) test_set_hook();
11567     test_DestroyWindow();
11568     test_DispatchMessage();
11569     test_SendMessageTimeout();
11570     test_edit_messages();
11571     test_quit_message();
11572     test_SetActiveWindow();
11573
11574     if (!pTrackMouseEvent)
11575         win_skip("TrackMouseEvent is not available\n");
11576     else
11577         test_TrackMouseEvent();
11578
11579     test_SetWindowRgn();
11580     test_sys_menu();
11581     test_dialog_messages();
11582     test_nullCallback();
11583     test_dbcs_wm_char();
11584     test_menu_messages();
11585     test_paintingloop();
11586     test_defwinproc();
11587     /* keep it the last test, under Windows it tends to break the tests
11588      * which rely on active/foreground windows being correct.
11589      */
11590     test_SetForegroundWindow();
11591
11592     UnhookWindowsHookEx(hCBT_hook);
11593     if (pUnhookWinEvent && hEvent_hook)
11594     {
11595         ret = pUnhookWinEvent(hEvent_hook);
11596         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11597         SetLastError(0xdeadbeef);
11598         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11599         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11600            GetLastError() == 0xdeadbeef, /* Win9x */
11601            "unexpected error %d\n", GetLastError());
11602     }
11603 }