d3dcompiler: Add argument check in D3DReflect().
[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 0x0600 /* For WM_CHANGEUISTATE,QS_RAWINPUT,WM_DWMxxxx */
24 #define WINVER 0x0600 /* for WM_GETTITLEBARINFOEX */
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35
36 #include "wine/test.h"
37
38 #define MDI_FIRST_CHILD_ID 2004
39
40 /* undocumented SWP flags - from SDK 3.1 */
41 #define SWP_NOCLIENTSIZE        0x0800
42 #define SWP_NOCLIENTMOVE        0x1000
43 #define SWP_STATECHANGED        0x8000
44
45 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
46
47 #ifndef WM_KEYF1
48 #define WM_KEYF1 0x004d
49 #endif
50
51 #ifndef WM_SYSTIMER
52 #define WM_SYSTIMER         0x0118
53 #endif
54
55 #define WND_PARENT_ID           1
56 #define WND_POPUP_ID            2
57 #define WND_CHILD_ID            3
58
59 #ifndef WM_LBTRACKPOINT
60 #define WM_LBTRACKPOINT  0x0131
61 #endif
62
63 /* encoded DRAWITEMSTRUCT into an LPARAM */
64 typedef struct
65 {
66     union
67     {
68         struct
69         {
70             UINT type    : 4;  /* ODT_* flags */
71             UINT ctl_id  : 4;  /* Control ID */
72             UINT item_id : 4;  /* Menu item ID */
73             UINT action  : 4;  /* ODA_* flags */
74             UINT state   : 16; /* ODS_* flags */
75         } item;
76         LPARAM lp;
77     } u;
78 } DRAW_ITEM_STRUCT;
79
80 static BOOL test_DestroyWindow_flag;
81 static HWINEVENTHOOK hEvent_hook;
82 static HHOOK hCBT_hook;
83 static DWORD cbt_hook_thread_id;
84
85 static const WCHAR testWindowClassW[] =
86 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
87
88 /*
89 FIXME: add tests for these
90 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
91  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
92  WS_THICKFRAME: thick border
93  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
94  WS_BORDER (default for overlapped windows): single black border
95  none (default for child (and popup?) windows): no border
96 */
97
98 typedef enum {
99     sent=0x1,
100     posted=0x2,
101     parent=0x4,
102     wparam=0x8,
103     lparam=0x10,
104     defwinproc=0x20,
105     beginpaint=0x40,
106     optional=0x80,
107     hook=0x100,
108     winevent_hook=0x200
109 } msg_flags_t;
110
111 struct message {
112     UINT message;          /* the WM_* code */
113     msg_flags_t flags;     /* message props */
114     WPARAM wParam;         /* expected value of wParam */
115     LPARAM lParam;         /* expected value of lParam */
116     WPARAM wp_mask;        /* mask for wParam checks */
117     LPARAM lp_mask;        /* mask for lParam checks */
118 };
119
120 struct recvd_message {
121     UINT message;          /* the WM_* code */
122     msg_flags_t flags;     /* message props */
123     HWND hwnd;             /* window that received the message */
124     WPARAM wParam;         /* expected value of wParam */
125     LPARAM lParam;         /* expected value of lParam */
126     int line;              /* source line where logged */
127     const char *descr;     /* description for trace output */
128     char output[512];      /* trace output */
129 };
130
131 /* Empty message sequence */
132 static const struct message WmEmptySeq[] =
133 {
134     { 0 }
135 };
136 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
137 static const struct message WmCreateOverlappedSeq[] = {
138     { HCBT_CREATEWND, hook },
139     { WM_GETMINMAXINFO, sent },
140     { WM_NCCREATE, sent },
141     { WM_NCCALCSIZE, sent|wparam, 0 },
142     { 0x0093, sent|defwinproc|optional },
143     { 0x0094, sent|defwinproc|optional },
144     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
145     { WM_CREATE, sent },
146     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
147     { 0 }
148 };
149 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
150  * for a not visible overlapped window.
151  */
152 static const struct message WmSWP_ShowOverlappedSeq[] = {
153     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
154     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
155     { WM_NCPAINT, sent|wparam|optional, 1 },
156     { WM_GETTEXT, sent|defwinproc|optional },
157     { WM_ERASEBKGND, sent|optional },
158     { HCBT_ACTIVATE, hook },
159     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
160     { WM_NOTIFYFORMAT, sent|optional },
161     { WM_QUERYUISTATE, sent|optional },
162     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
163     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
164     { WM_ACTIVATEAPP, sent|wparam, 1 },
165     { WM_NCACTIVATE, sent },
166     { WM_GETTEXT, sent|defwinproc|optional },
167     { WM_ACTIVATE, sent|wparam, 1 },
168     { HCBT_SETFOCUS, hook },
169     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
170     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
171     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
172     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
173     { WM_GETTEXT, sent|optional },
174     { WM_NCPAINT, sent|wparam|optional, 1 },
175     { WM_GETTEXT, sent|defwinproc|optional },
176     { WM_ERASEBKGND, sent|optional },
177     /* Win9x adds SWP_NOZORDER below */
178     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
179     { WM_GETTEXT, sent|optional },
180     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
181     { WM_NCPAINT, sent|wparam|optional, 1 },
182     { WM_ERASEBKGND, sent|optional },
183     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
184     { WM_SYNCPAINT, sent|optional },
185     { WM_GETTITLEBARINFOEX, sent|optional },
186     { WM_PAINT, sent|optional },
187     { WM_NCPAINT, sent|beginpaint|optional },
188     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
189     { WM_ERASEBKGND, sent|beginpaint|optional },
190     { 0 }
191 };
192 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
193  * for a visible overlapped window.
194  */
195 static const struct message WmSWP_HideOverlappedSeq[] = {
196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
197     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
198     { HCBT_ACTIVATE, hook|optional },
199     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
200     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
201     { WM_NCACTIVATE, sent|optional },
202     { WM_ACTIVATE, sent|optional },
203     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
204     { 0 }
205 };
206
207 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
208  * for a visible overlapped window.
209  */
210 static const struct message WmSWP_ResizeSeq[] = {
211     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
212     { WM_GETMINMAXINFO, sent|defwinproc },
213     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
214     { WM_NCPAINT, sent|optional },
215     { WM_GETTEXT, sent|defwinproc|optional },
216     { WM_ERASEBKGND, sent|optional },
217     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
218     { WM_SIZE, sent|defwinproc|optional },
219     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
220     { WM_NCPAINT, sent|optional },
221     { WM_GETTEXT, sent|defwinproc|optional },
222     { WM_ERASEBKGND, sent|optional },
223     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
224     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
225     { 0 }
226 };
227
228 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
229  * for a visible popup window.
230  */
231 static const struct message WmSWP_ResizePopupSeq[] = {
232     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
233     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
234     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
235     { WM_NCPAINT, sent|optional },
236     { WM_GETTEXT, sent|defwinproc|optional },
237     { WM_ERASEBKGND, sent|optional },
238     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
239     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
240     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
241     { WM_NCPAINT, sent|optional },
242     { WM_GETTEXT, sent|defwinproc|optional },
243     { WM_ERASEBKGND, sent|optional },
244     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
245     { 0 }
246 };
247
248 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
249  * for a visible overlapped window.
250  */
251 static const struct message WmSWP_MoveSeq[] = {
252     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
253     { WM_NCPAINT, sent|optional },
254     { WM_GETTEXT, sent|defwinproc|optional },
255     { WM_ERASEBKGND, sent|optional },
256     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
257     { WM_MOVE, sent|defwinproc|wparam, 0 },
258     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
259     { 0 }
260 };
261 /* Resize with SetWindowPos(SWP_NOZORDER)
262  * for a visible overlapped window
263  * SWP_NOZORDER is stripped by the logging code
264  */
265 static const struct message WmSWP_ResizeNoZOrder[] = {
266     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
267     { WM_GETMINMAXINFO, sent|defwinproc },
268     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
269     { WM_NCPAINT, sent|optional },
270     { WM_GETTEXT, sent|defwinproc|optional },
271     { WM_ERASEBKGND, sent|optional },
272     { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
273       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
274     { WM_MOVE, sent|defwinproc|optional },
275     { WM_SIZE, sent|defwinproc|optional },
276     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
277     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
278     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
279     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
280     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
281     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
282     { 0 }
283 };
284
285 /* Switch visible mdi children */
286 static const struct message WmSwitchChild[] = {
287     /* Switch MDI child */
288     { WM_MDIACTIVATE, sent },/* in the MDI client */
289     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
290     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
291     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
292     /* Deactivate 2nd MDI child */
293     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
294     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
295     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
296     /* Preparing for maximize and maximaze the 1st MDI child */
297     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
298     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
299     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
300     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
301     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
302     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
303     /* Lock redraw 2nd MDI child */
304     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
305     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
306     /* Restore 2nd MDI child */
307     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
308     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
309     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
310     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
311     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
312     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
313     /* Redraw 2nd MDI child */
314     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
315     /* Redraw MDI frame */
316     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
317     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
318     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
320     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
321     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
322     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
323     { HCBT_SETFOCUS, hook },
324     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
325     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
326     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
327     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
328     { WM_SETFOCUS, sent },/* in the MDI client */
329     { HCBT_SETFOCUS, hook },
330     { WM_KILLFOCUS, sent },/* in the MDI client */
331     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
332     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
333     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
334     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
335     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
336     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
337     { 0 }
338 };
339
340 /* Switch visible not maximized mdi children */
341 static const struct message WmSwitchNotMaximizedChild[] = {
342     /* Switch not maximized MDI child */
343     { WM_MDIACTIVATE, sent },/* in the MDI client */
344     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
345     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
346     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
347     /* Deactivate 1st MDI child */
348     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
349     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
350     /* Activate 2nd MDI child */
351     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
352     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
353     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
354     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
355     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
356     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
357     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
358     { HCBT_SETFOCUS, hook },
359     { WM_KILLFOCUS, sent }, /* in the  MDI client */
360     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
361     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
362     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
363     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
364     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
365     { 0 }
366 };
367
368
369 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
370                 SWP_NOZORDER|SWP_FRAMECHANGED)
371  * for a visible overlapped window with WS_CLIPCHILDREN style set.
372  */
373 static const struct message WmSWP_FrameChanged_clip[] = {
374     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
375     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
376     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
377     { WM_GETTEXT, sent|parent|defwinproc|optional },
378     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
379     { WM_NCPAINT, sent }, /* wparam != 1 */
380     { WM_ERASEBKGND, sent },
381     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
382     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
383     { WM_PAINT, sent },
384     { 0 }
385 };
386 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
387                 SWP_NOZORDER|SWP_FRAMECHANGED)
388  * for a visible overlapped window.
389  */
390 static const struct message WmSWP_FrameChangedDeferErase[] = {
391     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
392     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
393     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
394     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
395     { WM_PAINT, sent|parent|optional },
396     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
397     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
398     { WM_PAINT, sent },
399     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
400     { WM_ERASEBKGND, sent|beginpaint|optional },
401     { 0 }
402 };
403
404 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
405                 SWP_NOZORDER|SWP_FRAMECHANGED)
406  * for a visible overlapped window without WS_CLIPCHILDREN style set.
407  */
408 static const struct message WmSWP_FrameChanged_noclip[] = {
409     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
410     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
411     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
412     { WM_GETTEXT, sent|parent|defwinproc|optional },
413     { WM_ERASEBKGND, sent|parent|optional },
414     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
415     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
416     { WM_PAINT, sent },
417     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
418     { WM_ERASEBKGND, sent|beginpaint|optional },
419     { 0 }
420 };
421
422 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
423 static const struct message WmShowOverlappedSeq[] = {
424     { WM_SHOWWINDOW, sent|wparam, 1 },
425     { WM_NCPAINT, sent|wparam|optional, 1 },
426     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
427     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
428     { WM_NCPAINT, sent|wparam|optional, 1 },
429     { WM_GETTEXT, sent|defwinproc|optional },
430     { WM_ERASEBKGND, sent|optional },
431     { HCBT_ACTIVATE, hook },
432     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
433     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
434     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
435     { WM_NCPAINT, sent|wparam|optional, 1 },
436     { WM_ACTIVATEAPP, sent|wparam, 1 },
437     { WM_NCACTIVATE, sent|wparam, 1 },
438     { WM_GETTEXT, sent|defwinproc|optional },
439     { WM_ACTIVATE, sent|wparam, 1 },
440     { HCBT_SETFOCUS, hook },
441     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
442     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
443     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
444     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
445     { WM_GETTEXT, sent|optional },
446     { WM_NCPAINT, sent|wparam|optional, 1 },
447     { WM_GETTEXT, sent|defwinproc|optional },
448     { WM_ERASEBKGND, sent|optional },
449     /* Win9x adds SWP_NOZORDER below */
450     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
451     { WM_NCCALCSIZE, sent|optional },
452     { WM_GETTEXT, sent|optional },
453     { WM_NCPAINT, sent|optional },
454     { WM_ERASEBKGND, sent|optional },
455     { WM_SYNCPAINT, sent|optional },
456 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
457        * messages. Does that mean that CreateWindow doesn't set initial
458        * window dimensions for overlapped windows?
459        */
460     { WM_SIZE, sent },
461     { WM_MOVE, sent },
462 #endif
463     { WM_PAINT, sent|optional },
464     { WM_NCPAINT, sent|beginpaint|optional },
465     { 0 }
466 };
467 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
468 static const struct message WmShowMaxOverlappedSeq[] = {
469     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
470     { WM_GETMINMAXINFO, sent },
471     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
472     { WM_GETMINMAXINFO, sent|defwinproc },
473     { WM_NCCALCSIZE, sent|wparam, TRUE },
474     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
475     { HCBT_ACTIVATE, hook },
476     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
477     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
478     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
479     { WM_ACTIVATEAPP, sent|wparam, 1 },
480     { WM_NCACTIVATE, sent|wparam, 1 },
481     { WM_GETTEXT, sent|defwinproc|optional },
482     { WM_ACTIVATE, sent|wparam, 1 },
483     { HCBT_SETFOCUS, hook },
484     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
485     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
486     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
487     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
488     { WM_GETTEXT, sent|optional },
489     { WM_NCPAINT, sent|wparam|optional, 1 },
490     { WM_GETTEXT, sent|defwinproc|optional },
491     { WM_ERASEBKGND, sent|optional },
492     /* Win9x adds SWP_NOZORDER below */
493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
494     { WM_MOVE, sent|defwinproc },
495     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
496     { WM_GETTEXT, sent|optional },
497     { WM_NCCALCSIZE, sent|optional },
498     { WM_NCPAINT, sent|optional },
499     { WM_ERASEBKGND, sent|optional },
500     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
501     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
502     { WM_SYNCPAINT, sent|optional },
503     { WM_GETTITLEBARINFOEX, sent|optional },
504     { WM_PAINT, sent|optional },
505     { WM_NCPAINT, sent|beginpaint|optional },
506     { WM_ERASEBKGND, sent|beginpaint|optional },
507     { 0 }
508 };
509 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
510 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
511     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
512     { WM_GETTEXT, sent|optional },
513     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
514     { WM_GETMINMAXINFO, sent|defwinproc },
515     { WM_NCCALCSIZE, sent|wparam, TRUE },
516     { WM_NCPAINT, sent|optional },
517     { WM_GETTEXT, sent|defwinproc|optional },
518     { WM_ERASEBKGND, sent|optional },
519     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
520     { WM_MOVE, sent|defwinproc|optional },
521     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
522     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
523     { WM_NCPAINT, sent|optional },
524     { WM_ERASEBKGND, sent|optional },
525     { WM_PAINT, sent|optional },
526     { WM_GETTITLEBARINFOEX, sent|optional },
527     { WM_NCPAINT, sent|beginpaint|optional },
528     { WM_ERASEBKGND, sent|beginpaint|optional },
529     { 0 }
530 };
531 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
532 static const struct message WmShowRestoreMinOverlappedSeq[] = {
533     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
534     { WM_QUERYOPEN, sent|optional },
535     { WM_GETTEXT, sent|optional },
536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
537     { WM_GETMINMAXINFO, sent|defwinproc },
538     { WM_NCCALCSIZE, sent|wparam, TRUE },
539     { HCBT_ACTIVATE, hook },
540     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
541     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
542     { WM_ACTIVATEAPP, sent|wparam, 1 },
543     { WM_NCACTIVATE, sent|wparam, 1 },
544     { WM_GETTEXT, sent|defwinproc|optional },
545     { WM_ACTIVATE, sent|wparam, 1 },
546     { HCBT_SETFOCUS, hook },
547     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
548     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
549     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
550     { WM_GETTEXT, sent|optional },
551     { WM_NCPAINT, sent|wparam|optional, 1 },
552     { WM_GETTEXT, sent|defwinproc|optional },
553     { WM_ERASEBKGND, sent },
554     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
555     { WM_MOVE, sent|defwinproc },
556     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
557     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
558     { WM_NCPAINT, sent|wparam|optional, 1 },
559     { WM_ERASEBKGND, sent|optional },
560     { WM_ACTIVATE, sent|wparam, 1 },
561     { WM_GETTEXT, sent|optional },
562     { WM_PAINT, sent|optional },
563     { WM_GETTITLEBARINFOEX, sent|optional },
564     { WM_NCPAINT, sent|beginpaint|optional },
565     { WM_ERASEBKGND, sent|beginpaint|optional },
566     { 0 }
567 };
568 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
569 static const struct message WmShowMinOverlappedSeq[] = {
570     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
571     { HCBT_SETFOCUS, hook },
572     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
573     { WM_KILLFOCUS, sent },
574     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
575     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
576     { WM_GETTEXT, sent|optional },
577     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
578     { WM_GETMINMAXINFO, sent|defwinproc },
579     { WM_NCCALCSIZE, sent|wparam, TRUE },
580     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
581     { WM_NCPAINT, sent|optional },
582     { WM_GETTEXT, sent|defwinproc|optional },
583     { WM_WINDOWPOSCHANGED, sent },
584     { WM_MOVE, sent|defwinproc },
585     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
586     { WM_NCCALCSIZE, sent|optional },
587     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
588     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
589     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
590     { WM_NCACTIVATE, sent|wparam, 0 },
591     { WM_GETTEXT, sent|defwinproc|optional },
592     { WM_ACTIVATE, sent },
593     { WM_ACTIVATEAPP, sent|wparam, 0 },
594
595     /* Vista sometimes restores the window right away... */
596     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
597     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
598     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
599     { WM_QUERYOPEN, sent|optional },
600     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
601     { WM_GETMINMAXINFO, sent|optional|defwinproc },
602     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
603     { HCBT_ACTIVATE, hook|optional },
604     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
605     { WM_NCACTIVATE, sent|optional },
606     { WM_GETTEXT, sent|optional },
607     { WM_ACTIVATE, sent|optional|wparam, 1 },
608     { HCBT_SETFOCUS, hook|optional },
609     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
610     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
611     { WM_SETFOCUS, sent|optional },
612     { WM_NCPAINT, sent|optional },
613     { WM_GETTEXT, sent|defwinproc|optional },
614     { WM_ERASEBKGND, sent|optional },
615     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
616     { WM_MOVE, sent|defwinproc|optional },
617     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
618     { WM_ACTIVATE, sent|optional|wparam, 1 },
619     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
620     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
621
622     { WM_PAINT, sent|optional },
623     { WM_NCPAINT, sent|beginpaint|optional },
624     { WM_ERASEBKGND, sent|beginpaint|optional },
625     { 0 }
626 };
627 /* ShowWindow(SW_HIDE) for a visible overlapped window */
628 static const struct message WmHideOverlappedSeq[] = {
629     { WM_SHOWWINDOW, sent|wparam, 0 },
630     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
631     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
633     { WM_SIZE, sent|optional }, /* XP doesn't send it */
634     { WM_MOVE, sent|optional }, /* XP doesn't send it */
635     { WM_NCACTIVATE, sent|wparam|optional, 0 },
636     { WM_ACTIVATE, sent|wparam|optional, 0 },
637     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
638     { HCBT_SETFOCUS, hook|optional },
639     { WM_KILLFOCUS, sent|wparam, 0 },
640     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
641     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
642     { 0 }
643 };
644 /* DestroyWindow for a visible overlapped window */
645 static const struct message WmDestroyOverlappedSeq[] = {
646     { HCBT_DESTROYWND, hook },
647     { 0x0090, sent|optional },
648     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
649     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
650     { 0x0090, sent|optional },
651     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
652     { WM_NCACTIVATE, sent|optional|wparam, 0 },
653     { WM_ACTIVATE, sent|optional },
654     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
655     { WM_KILLFOCUS, sent|optional|wparam, 0 },
656     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
657     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
658     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
659     { WM_DESTROY, sent },
660     { WM_NCDESTROY, sent },
661     { 0 }
662 };
663 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
664 static const struct message WmCreateMaxPopupSeq[] = {
665     { HCBT_CREATEWND, hook },
666     { WM_NCCREATE, sent },
667     { WM_NCCALCSIZE, sent|wparam, 0 },
668     { WM_CREATE, sent },
669     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
670     { WM_SIZE, sent|wparam, SIZE_RESTORED },
671     { WM_MOVE, sent },
672     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
673     { WM_GETMINMAXINFO, sent },
674     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
675     { WM_NCCALCSIZE, sent|wparam, TRUE },
676     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
677     { WM_MOVE, sent|defwinproc },
678     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
679     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
680     { WM_SHOWWINDOW, sent|wparam, 1 },
681     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
682     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
683     { HCBT_ACTIVATE, hook },
684     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
685     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
686     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
687     { WM_NCPAINT, sent|wparam|optional, 1 },
688     { WM_ERASEBKGND, sent|optional },
689     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
690     { WM_ACTIVATEAPP, sent|wparam, 1 },
691     { WM_NCACTIVATE, sent },
692     { WM_ACTIVATE, sent|wparam, 1 },
693     { HCBT_SETFOCUS, hook },
694     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
695     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
696     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
697     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
698     { WM_GETTEXT, sent|optional },
699     { WM_SYNCPAINT, sent|wparam|optional, 4 },
700     { WM_NCPAINT, sent|wparam|optional, 1 },
701     { WM_ERASEBKGND, sent|optional },
702     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
703     { WM_ERASEBKGND, sent|defwinproc|optional },
704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
705     { 0 }
706 };
707 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
708 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
709     { HCBT_CREATEWND, hook },
710     { WM_NCCREATE, sent },
711     { WM_NCCALCSIZE, sent|wparam, 0 },
712     { WM_CREATE, sent },
713     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
714     { WM_SIZE, sent|wparam, SIZE_RESTORED },
715     { WM_MOVE, sent },
716     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
717     { WM_GETMINMAXINFO, sent },
718     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
719     { WM_NCCALCSIZE, sent|wparam, TRUE },
720     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
721     { WM_MOVE, sent|defwinproc },
722     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
723     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
724     { 0 }
725 };
726 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
727 static const struct message WmShowMaxPopupResizedSeq[] = {
728     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
729     { WM_GETMINMAXINFO, sent },
730     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
731     { WM_NCCALCSIZE, sent|wparam, TRUE },
732     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
733     { HCBT_ACTIVATE, hook },
734     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
735     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
736     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
737     { WM_NCPAINT, sent|wparam|optional, 1 },
738     { WM_ERASEBKGND, sent|optional },
739     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
740     { WM_ACTIVATEAPP, sent|wparam, 1 },
741     { WM_NCACTIVATE, sent },
742     { WM_ACTIVATE, sent|wparam, 1 },
743     { HCBT_SETFOCUS, hook },
744     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
745     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
746     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
747     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
748     { WM_GETTEXT, sent|optional },
749     { WM_NCPAINT, sent|wparam|optional, 1 },
750     { WM_ERASEBKGND, sent|optional },
751     { WM_WINDOWPOSCHANGED, sent },
752     /* WinNT4.0 sends WM_MOVE */
753     { WM_MOVE, sent|defwinproc|optional },
754     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
755     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
756     { 0 }
757 };
758 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
759 static const struct message WmShowMaxPopupSeq[] = {
760     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
761     { WM_GETMINMAXINFO, sent },
762     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
763     { WM_NCCALCSIZE, sent|wparam, TRUE },
764     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
765     { HCBT_ACTIVATE, hook },
766     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
767     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
768     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
769     { WM_ACTIVATEAPP, sent|wparam, 1 },
770     { WM_NCACTIVATE, sent },
771     { WM_ACTIVATE, sent|wparam, 1 },
772     { HCBT_SETFOCUS, hook },
773     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
774     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
775     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
776     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
777     { WM_GETTEXT, sent|optional },
778     { WM_SYNCPAINT, sent|wparam|optional, 4 },
779     { WM_NCPAINT, sent|wparam|optional, 1 },
780     { WM_ERASEBKGND, sent|optional },
781     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
782     { WM_ERASEBKGND, sent|defwinproc|optional },
783     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
784     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
785     { 0 }
786 };
787 /* CreateWindow(WS_VISIBLE) for popup window */
788 static const struct message WmCreatePopupSeq[] = {
789     { HCBT_CREATEWND, hook },
790     { WM_NCCREATE, sent },
791     { WM_NCCALCSIZE, sent|wparam, 0 },
792     { WM_CREATE, sent },
793     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
794     { WM_SIZE, sent|wparam, SIZE_RESTORED },
795     { WM_MOVE, sent },
796     { WM_SHOWWINDOW, sent|wparam, 1 },
797     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
798     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
799     { HCBT_ACTIVATE, hook },
800     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
801     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
802     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
803     { WM_NCPAINT, sent|wparam|optional, 1 },
804     { WM_ERASEBKGND, sent|optional },
805     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
806     { WM_ACTIVATEAPP, sent|wparam, 1 },
807     { WM_NCACTIVATE, sent },
808     { WM_ACTIVATE, sent|wparam, 1 },
809     { HCBT_SETFOCUS, hook },
810     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
811     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
812     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
813     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
814     { WM_GETTEXT, sent|optional },
815     { WM_SYNCPAINT, sent|wparam|optional, 4 },
816     { WM_NCPAINT, sent|wparam|optional, 1 },
817     { WM_ERASEBKGND, sent|optional },
818     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
819     { 0 }
820 };
821 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
822 static const struct message WmShowVisMaxPopupSeq[] = {
823     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
824     { WM_GETMINMAXINFO, sent },
825     { WM_GETTEXT, sent|optional },
826     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
827     { WM_GETTEXT, sent|optional },
828     { WM_NCCALCSIZE, sent|wparam, TRUE },
829     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
830     { WM_NCPAINT, sent|wparam|optional, 1 },
831     { WM_ERASEBKGND, sent|optional },
832     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
833     { WM_MOVE, sent|defwinproc },
834     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
835     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
836     { 0 }
837 };
838 /* CreateWindow (for a child popup window, not initially visible) */
839 static const struct message WmCreateChildPopupSeq[] = {
840     { HCBT_CREATEWND, hook },
841     { WM_NCCREATE, sent }, 
842     { WM_NCCALCSIZE, sent|wparam, 0 },
843     { WM_CREATE, sent },
844     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
845     { WM_SIZE, sent|wparam, SIZE_RESTORED },
846     { WM_MOVE, sent },
847     { 0 }
848 };
849 /* CreateWindow (for a popup window, not initially visible,
850  * which sets WS_VISIBLE in WM_CREATE handler)
851  */
852 static const struct message WmCreateInvisiblePopupSeq[] = {
853     { HCBT_CREATEWND, hook },
854     { WM_NCCREATE, sent }, 
855     { WM_NCCALCSIZE, sent|wparam, 0 },
856     { WM_CREATE, sent },
857     { WM_STYLECHANGING, sent },
858     { WM_STYLECHANGED, sent },
859     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
860     { WM_SIZE, sent|wparam, SIZE_RESTORED },
861     { WM_MOVE, sent },
862     { 0 }
863 };
864 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
865  * for a popup window with WS_VISIBLE style set
866  */
867 static const struct message WmShowVisiblePopupSeq_2[] = {
868     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
869     { 0 }
870 };
871 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
872  * for a popup window with WS_VISIBLE style set
873  */
874 static const struct message WmShowVisiblePopupSeq_3[] = {
875     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
876     { HCBT_ACTIVATE, hook },
877     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
878     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
879     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
880     { WM_NCACTIVATE, sent },
881     { WM_ACTIVATE, sent|wparam, 1 },
882     { HCBT_SETFOCUS, hook },
883     { WM_KILLFOCUS, sent|parent },
884     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
885     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
886     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
887     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
888     { WM_SETFOCUS, sent|defwinproc },
889     { WM_GETTEXT, sent|optional },
890     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
891     { 0 }
892 };
893 /* CreateWindow (for child window, not initially visible) */
894 static const struct message WmCreateChildSeq[] = {
895     { HCBT_CREATEWND, hook },
896     { WM_NCCREATE, sent }, 
897     /* child is inserted into parent's child list after WM_NCCREATE returns */
898     { WM_NCCALCSIZE, sent|wparam, 0 },
899     { WM_CREATE, sent },
900     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
901     { WM_SIZE, sent|wparam, SIZE_RESTORED },
902     { WM_MOVE, sent },
903     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
904     { 0 }
905 };
906 /* CreateWindow (for maximized child window, not initially visible) */
907 static const struct message WmCreateMaximizedChildSeq[] = {
908     { HCBT_CREATEWND, hook },
909     { WM_NCCREATE, sent }, 
910     { WM_NCCALCSIZE, sent|wparam, 0 },
911     { WM_CREATE, sent },
912     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
913     { WM_SIZE, sent|wparam, SIZE_RESTORED },
914     { WM_MOVE, sent },
915     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
916     { WM_GETMINMAXINFO, sent },
917     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
918     { WM_NCCALCSIZE, sent|wparam, 1 },
919     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
920     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
921     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
922     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
923     { 0 }
924 };
925 /* CreateWindow (for a child window, initially visible) */
926 static const struct message WmCreateVisibleChildSeq[] = {
927     { HCBT_CREATEWND, hook },
928     { WM_NCCREATE, sent }, 
929     /* child is inserted into parent's child list after WM_NCCREATE returns */
930     { WM_NCCALCSIZE, sent|wparam, 0 },
931     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
932     { WM_CREATE, sent },
933     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
934     { WM_SIZE, sent|wparam, SIZE_RESTORED },
935     { WM_MOVE, sent },
936     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
937     { WM_SHOWWINDOW, sent|wparam, 1 },
938     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
939     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
940     { WM_ERASEBKGND, sent|parent|optional },
941     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
942     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
943     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
944     { 0 }
945 };
946 /* ShowWindow(SW_SHOW) for a not visible child window */
947 static const struct message WmShowChildSeq[] = {
948     { WM_SHOWWINDOW, sent|wparam, 1 },
949     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
950     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
951     { WM_ERASEBKGND, sent|parent|optional },
952     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
953     { 0 }
954 };
955 /* ShowWindow(SW_HIDE) for a visible child window */
956 static const struct message WmHideChildSeq[] = {
957     { WM_SHOWWINDOW, sent|wparam, 0 },
958     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
959     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
960     { WM_ERASEBKGND, sent|parent|optional },
961     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
962     { 0 }
963 };
964 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
965 static const struct message WmHideChildSeq2[] = {
966     { WM_SHOWWINDOW, sent|wparam, 0 },
967     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
968     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
969     { WM_ERASEBKGND, sent|parent|optional },
970     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
971     { 0 }
972 };
973 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
974  * for a not visible child window
975  */
976 static const struct message WmShowChildSeq_2[] = {
977     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
978     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
979     { WM_CHILDACTIVATE, sent },
980     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
981     { 0 }
982 };
983 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
984  * for a not visible child window
985  */
986 static const struct message WmShowChildSeq_3[] = {
987     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
988     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
989     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
990     { 0 }
991 };
992 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
993  * for a visible child window with a caption
994  */
995 static const struct message WmShowChildSeq_4[] = {
996     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
997     { WM_CHILDACTIVATE, sent },
998     { 0 }
999 };
1000 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1001 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1002     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1003     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1004     { WM_NCCALCSIZE, sent|wparam, 1 },
1005     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1006     { WM_CHILDACTIVATE, sent|optional },
1007     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1008     { WM_MOVE, sent|defwinproc },
1009     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1010     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1011     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1012     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1013     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1014     { WM_GETTEXT, sent|optional },
1015     { 0 }
1016 };
1017 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1018 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1019     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1020     { 0 }
1021 };
1022 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1023 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1024     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1025     { WM_GETMINMAXINFO, sent },
1026     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1027     { WM_NCCALCSIZE, sent|wparam, 1 },
1028     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1029     { WM_CHILDACTIVATE, sent },
1030     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1031     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1032     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1033     { 0 }
1034 };
1035 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1036 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1037     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1038     { 0 }
1039 };
1040 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1041 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1042     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1043     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1044     { WM_NCCALCSIZE, sent|wparam, 1 },
1045     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1046     { WM_CHILDACTIVATE, sent },
1047     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1048     { WM_MOVE, sent|defwinproc },
1049     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1050     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1051     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1052     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1053     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1054     { WM_GETTEXT, sent|optional },
1055     { 0 }
1056 };
1057 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1058 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1059     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1060     { 0 }
1061 };
1062 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1063 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1064     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1065     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1066     { WM_NCCALCSIZE, sent|wparam, 1 },
1067     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1068     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1069     { WM_MOVE, sent|defwinproc },
1070     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1071     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1072     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1073     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1074     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1075     { WM_GETTEXT, sent|optional },
1076     { 0 }
1077 };
1078 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1079 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1080     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1081     { 0 }
1082 };
1083 /* ShowWindow(SW_SHOW) for child with invisible parent */
1084 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1085     { WM_SHOWWINDOW, sent|wparam, 1 },
1086     { 0 }
1087 };
1088 /* ShowWindow(SW_HIDE) for child with invisible parent */
1089 static const struct message WmHideChildInvisibleParentSeq[] = {
1090     { WM_SHOWWINDOW, sent|wparam, 0 },
1091     { 0 }
1092 };
1093 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1094 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1095     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1096     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1097     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1098     { 0 }
1099 };
1100 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1101 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1102     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1103     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1104     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1105     { 0 }
1106 };
1107 /* DestroyWindow for a visible child window */
1108 static const struct message WmDestroyChildSeq[] = {
1109     { HCBT_DESTROYWND, hook },
1110     { 0x0090, sent|optional },
1111     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1112     { WM_SHOWWINDOW, sent|wparam, 0 },
1113     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1114     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1115     { WM_ERASEBKGND, sent|parent|optional },
1116     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1117     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1118     { WM_KILLFOCUS, sent },
1119     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1120     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1121     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1122     { WM_SETFOCUS, sent|parent },
1123     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1124     { WM_DESTROY, sent },
1125     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1126     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1127     { WM_NCDESTROY, sent },
1128     { 0 }
1129 };
1130 /* visible child window destroyed by thread exit */
1131 static const struct message WmExitThreadSeq[] = {
1132     { WM_NCDESTROY, sent },  /* actually in grandchild */
1133     { WM_PAINT, sent|parent },
1134     { WM_ERASEBKGND, sent|parent|beginpaint },
1135     { 0 }
1136 };
1137 /* DestroyWindow for a visible child window with invisible parent */
1138 static const struct message WmDestroyInvisibleChildSeq[] = {
1139     { HCBT_DESTROYWND, hook },
1140     { 0x0090, sent|optional },
1141     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1142     { WM_SHOWWINDOW, sent|wparam, 0 },
1143     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1144     { WM_DESTROY, sent },
1145     { WM_NCDESTROY, sent },
1146     { 0 }
1147 };
1148 /* Moving the mouse in nonclient area */
1149 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1150     { WM_NCHITTEST, sent },
1151     { WM_SETCURSOR, sent },
1152     { WM_NCMOUSEMOVE, posted },
1153     { 0 }
1154 };
1155 /* Moving the mouse in client area */
1156 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1157     { WM_NCHITTEST, sent },
1158     { WM_SETCURSOR, sent },
1159     { WM_MOUSEMOVE, posted },
1160     { 0 }
1161 };
1162 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1163 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1164     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1165     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1166     { WM_GETMINMAXINFO, sent|defwinproc },
1167     { WM_ENTERSIZEMOVE, sent|defwinproc },
1168     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1169     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1170     { WM_MOVE, sent|defwinproc },
1171     { WM_EXITSIZEMOVE, sent|defwinproc },
1172     { 0 }
1173 };
1174 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1175 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1176     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1177     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1178     { WM_GETMINMAXINFO, sent|defwinproc },
1179     { WM_ENTERSIZEMOVE, sent|defwinproc },
1180     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1181     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1182     { WM_GETMINMAXINFO, sent|defwinproc },
1183     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1184     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1185     { WM_GETTEXT, sent|defwinproc },
1186     { WM_ERASEBKGND, sent|defwinproc },
1187     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1188     { WM_MOVE, sent|defwinproc },
1189     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1190     { WM_EXITSIZEMOVE, sent|defwinproc },
1191     { 0 }
1192 };
1193 /* Resizing child window with MoveWindow (32) */
1194 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1196     { WM_NCCALCSIZE, sent|wparam, 1 },
1197     { WM_ERASEBKGND, sent|parent|optional },
1198     { WM_ERASEBKGND, sent|optional },
1199     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1200     { WM_MOVE, sent|defwinproc },
1201     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1202     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1203     { 0 }
1204 };
1205 /* Clicking on inactive button */
1206 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1207     { WM_NCHITTEST, sent },
1208     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1209     { WM_MOUSEACTIVATE, sent },
1210     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1211     { WM_SETCURSOR, sent },
1212     { WM_SETCURSOR, sent|parent|defwinproc },
1213     { WM_LBUTTONDOWN, posted },
1214     { WM_KILLFOCUS, posted|parent },
1215     { WM_SETFOCUS, posted },
1216     { WM_CTLCOLORBTN, posted|parent },
1217     { BM_SETSTATE, posted },
1218     { WM_CTLCOLORBTN, posted|parent },
1219     { WM_LBUTTONUP, posted },
1220     { BM_SETSTATE, posted },
1221     { WM_CTLCOLORBTN, posted|parent },
1222     { WM_COMMAND, posted|parent },
1223     { 0 }
1224 };
1225 /* Reparenting a button (16/32) */
1226 /* The last child (button) reparented gets topmost for its new parent. */
1227 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1228     { WM_SHOWWINDOW, sent|wparam, 0 },
1229     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1230     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1231     { WM_ERASEBKGND, sent|parent },
1232     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1233     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1234     { WM_CHILDACTIVATE, sent },
1235     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1236     { WM_MOVE, sent|defwinproc },
1237     { WM_SHOWWINDOW, sent|wparam, 1 },
1238     { 0 }
1239 };
1240 /* Creation of a custom dialog (32) */
1241 static const struct message WmCreateCustomDialogSeq[] = {
1242     { HCBT_CREATEWND, hook },
1243     { WM_GETMINMAXINFO, sent },
1244     { WM_NCCREATE, sent },
1245     { WM_NCCALCSIZE, sent|wparam, 0 },
1246     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1247     { WM_CREATE, sent },
1248     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1249     { WM_NOTIFYFORMAT, sent|optional },
1250     { WM_QUERYUISTATE, sent|optional },
1251     { WM_WINDOWPOSCHANGING, sent|optional },
1252     { WM_GETMINMAXINFO, sent|optional },
1253     { WM_NCCALCSIZE, sent|optional },
1254     { WM_WINDOWPOSCHANGED, sent|optional },
1255     { WM_SHOWWINDOW, sent|wparam, 1 },
1256     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1257     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1258     { HCBT_ACTIVATE, hook },
1259     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1260
1261
1262     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1263
1264     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1265
1266     { WM_NCACTIVATE, sent },
1267     { WM_GETTEXT, sent|optional|defwinproc },
1268     { WM_GETTEXT, sent|optional|defwinproc },
1269     { WM_GETTEXT, sent|optional|defwinproc },
1270     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1271     { WM_ACTIVATE, sent|wparam, 1 },
1272     { WM_GETTEXT, sent|optional },
1273     { WM_KILLFOCUS, sent|parent },
1274     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1275     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1276     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1277     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1278     { WM_SETFOCUS, sent },
1279     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1280     { WM_NCPAINT, sent|wparam, 1 },
1281     { WM_GETTEXT, sent|optional|defwinproc },
1282     { WM_GETTEXT, sent|optional|defwinproc },
1283     { WM_ERASEBKGND, sent },
1284     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1285     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1286     { WM_GETTEXT, sent|optional },
1287     { WM_GETTEXT, sent|optional },
1288     { WM_NCCALCSIZE, sent|optional },
1289     { WM_NCPAINT, sent|optional },
1290     { WM_GETTEXT, sent|optional|defwinproc },
1291     { WM_GETTEXT, sent|optional|defwinproc },
1292     { WM_ERASEBKGND, sent|optional },
1293     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1294     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1295     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1296     { WM_MOVE, sent },
1297     { 0 }
1298 };
1299 /* Calling EndDialog for a custom dialog (32) */
1300 static const struct message WmEndCustomDialogSeq[] = {
1301     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1302     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1303     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1304     { WM_GETTEXT, sent|optional },
1305     { HCBT_ACTIVATE, hook },
1306     { WM_NCACTIVATE, sent|wparam, 0 },
1307     { WM_GETTEXT, sent|optional|defwinproc },
1308     { WM_GETTEXT, sent|optional|defwinproc },
1309     { WM_ACTIVATE, sent|wparam, 0 },
1310     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1311     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1312     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1313     { WM_GETTEXT, sent|optional|defwinproc },
1314     { WM_GETTEXT, sent|optional|defwinproc },
1315     { HCBT_SETFOCUS, hook },
1316     { WM_KILLFOCUS, sent },
1317     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1318     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1319     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1320     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1321     { WM_SETFOCUS, sent|parent|defwinproc },
1322     { 0 }
1323 };
1324 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1325 static const struct message WmShowCustomDialogSeq[] = {
1326     { WM_SHOWWINDOW, sent|wparam, 1 },
1327     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1328     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1329     { HCBT_ACTIVATE, hook },
1330     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1331
1332     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1333
1334     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1335     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1336     { WM_NCACTIVATE, sent },
1337     { WM_ACTIVATE, sent|wparam, 1 },
1338     { WM_GETTEXT, sent|optional },
1339
1340     { WM_KILLFOCUS, sent|parent },
1341     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1342     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1343     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1344     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1345     { WM_SETFOCUS, sent },
1346     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1347     { WM_NCPAINT, sent|wparam, 1 },
1348     { WM_ERASEBKGND, sent },
1349     { WM_CTLCOLORDLG, sent|defwinproc },
1350     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1351     { 0 }
1352 };
1353 /* Creation and destruction of a modal dialog (32) */
1354 static const struct message WmModalDialogSeq[] = {
1355     { WM_CANCELMODE, sent|parent },
1356     { HCBT_SETFOCUS, hook },
1357     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1358     { WM_KILLFOCUS, sent|parent },
1359     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1360     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1361     { WM_ENABLE, sent|parent|wparam, 0 },
1362     { HCBT_CREATEWND, hook },
1363     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1364     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1365     { WM_SETFONT, sent },
1366     { WM_INITDIALOG, sent },
1367     { WM_CHANGEUISTATE, sent|optional },
1368     { WM_UPDATEUISTATE, sent|optional },
1369     { WM_SHOWWINDOW, sent },
1370     { HCBT_ACTIVATE, hook },
1371     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1372     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1373     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1374     { WM_NCACTIVATE, sent },
1375     { WM_GETTEXT, sent|optional },
1376     { WM_ACTIVATE, sent|wparam, 1 },
1377     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1378     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1379     { WM_NCPAINT, sent|optional },
1380     { WM_GETTEXT, sent|optional },
1381     { WM_ERASEBKGND, sent|optional },
1382     { WM_CTLCOLORDLG, sent|optional },
1383     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1384     { WM_GETTEXT, sent|optional },
1385     { WM_NCCALCSIZE, sent|optional },
1386     { WM_NCPAINT, sent|optional },
1387     { WM_GETTEXT, sent|optional },
1388     { WM_ERASEBKGND, sent|optional },
1389     { WM_CTLCOLORDLG, sent|optional },
1390     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1391     { WM_PAINT, sent|optional },
1392     { WM_CTLCOLORBTN, sent|optional },
1393     { WM_GETTITLEBARINFOEX, sent|optional },
1394     { WM_ENTERIDLE, sent|parent|optional },
1395     { WM_ENTERIDLE, sent|parent|optional },
1396     { WM_ENTERIDLE, sent|parent|optional },
1397     { WM_ENTERIDLE, sent|parent|optional },
1398     { WM_ENTERIDLE, sent|parent|optional },
1399     { WM_ENTERIDLE, sent|parent|optional },
1400     { WM_ENTERIDLE, sent|parent|optional },
1401     { WM_ENTERIDLE, sent|parent|optional },
1402     { WM_ENTERIDLE, sent|parent|optional },
1403     { WM_ENTERIDLE, sent|parent|optional },
1404     { WM_ENTERIDLE, sent|parent|optional },
1405     { WM_ENTERIDLE, sent|parent|optional },
1406     { WM_ENTERIDLE, sent|parent|optional },
1407     { WM_ENTERIDLE, sent|parent|optional },
1408     { WM_ENTERIDLE, sent|parent|optional },
1409     { WM_ENTERIDLE, sent|parent|optional },
1410     { WM_ENTERIDLE, sent|parent|optional },
1411     { WM_ENTERIDLE, sent|parent|optional },
1412     { WM_ENTERIDLE, sent|parent|optional },
1413     { WM_ENTERIDLE, sent|parent|optional },
1414     { WM_TIMER, sent },
1415     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1416     { WM_ENABLE, sent|parent|wparam, 1 },
1417     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1418     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1419     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1420     { WM_GETTEXT, sent|optional },
1421     { HCBT_ACTIVATE, hook },
1422     { WM_NCACTIVATE, sent|wparam, 0 },
1423     { WM_GETTEXT, sent|optional },
1424     { WM_ACTIVATE, sent|wparam, 0 },
1425     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1426     { WM_WINDOWPOSCHANGING, sent|optional },
1427     { WM_WINDOWPOSCHANGED, sent|optional },
1428     { HCBT_SETFOCUS, hook },
1429     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1430     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1431     { WM_SETFOCUS, sent|parent|defwinproc },
1432     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1433     { HCBT_DESTROYWND, hook },
1434     { 0x0090, sent|optional },
1435     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1436     { WM_DESTROY, sent },
1437     { WM_NCDESTROY, sent },
1438     { 0 }
1439 };
1440 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1441 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1442     /* (inside dialog proc, handling WM_INITDIALOG) */
1443     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1444     { WM_NCCALCSIZE, sent },
1445     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1446     { WM_GETTEXT, sent|defwinproc },
1447     { WM_ACTIVATE, sent|parent|wparam, 0 },
1448     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1449     { WM_WINDOWPOSCHANGING, sent|parent },
1450     { WM_NCACTIVATE, sent|wparam, 1 },
1451     { WM_ACTIVATE, sent|wparam, 1 },
1452     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1453     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1454     /* (setting focus) */
1455     { WM_SHOWWINDOW, sent|wparam, 1 },
1456     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1457     { WM_NCPAINT, sent },
1458     { WM_GETTEXT, sent|defwinproc },
1459     { WM_ERASEBKGND, sent },
1460     { WM_CTLCOLORDLG, sent|defwinproc },
1461     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1462     { WM_PAINT, sent },
1463     /* (bunch of WM_CTLCOLOR* for each control) */
1464     { WM_PAINT, sent|parent },
1465     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1466     { WM_SETCURSOR, sent|parent },
1467     { 0 }
1468 };
1469 /* SetMenu for NonVisible windows with size change*/
1470 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1471     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1472     { WM_NCCALCSIZE, sent|wparam, 1 },
1473     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1474     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1475     { WM_MOVE, sent|defwinproc },
1476     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1477     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1478     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1479     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1480     { WM_GETTEXT, sent|optional },
1481     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1482     { 0 }
1483 };
1484 /* SetMenu for NonVisible windows with no size change */
1485 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1486     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1487     { WM_NCCALCSIZE, sent|wparam, 1 },
1488     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1489     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1490     { 0 }
1491 };
1492 /* SetMenu for Visible windows with size change */
1493 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1494     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1495     { WM_NCCALCSIZE, sent|wparam, 1 },
1496     { 0x0093, sent|defwinproc|optional },
1497     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1498     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1499     { 0x0093, sent|defwinproc|optional },
1500     { 0x0093, sent|defwinproc|optional },
1501     { 0x0091, sent|defwinproc|optional },
1502     { 0x0092, sent|defwinproc|optional },
1503     { WM_GETTEXT, sent|defwinproc|optional },
1504     { WM_ERASEBKGND, sent|optional },
1505     { WM_ACTIVATE, sent|optional },
1506     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1507     { WM_MOVE, sent|defwinproc },
1508     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1509     { 0x0093, sent|optional },
1510     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1511     { 0x0093, sent|defwinproc|optional },
1512     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1513     { 0x0093, sent|defwinproc|optional },
1514     { 0x0093, sent|defwinproc|optional },
1515     { 0x0091, sent|defwinproc|optional },
1516     { 0x0092, sent|defwinproc|optional },
1517     { WM_ERASEBKGND, sent|optional },
1518     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1519     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1520     { 0 }
1521 };
1522 /* SetMenu for Visible windows with no size change */
1523 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1524     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1525     { WM_NCCALCSIZE, sent|wparam, 1 },
1526     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1527     { WM_GETTEXT, sent|defwinproc|optional },
1528     { WM_ERASEBKGND, sent|optional },
1529     { WM_ACTIVATE, sent|optional },
1530     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1531     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1532     { 0 }
1533 };
1534 /* DrawMenuBar for a visible window */
1535 static const struct message WmDrawMenuBarSeq[] =
1536 {
1537     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1538     { WM_NCCALCSIZE, sent|wparam, 1 },
1539     { 0x0093, sent|defwinproc|optional },
1540     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1541     { 0x0093, sent|defwinproc|optional },
1542     { 0x0093, sent|defwinproc|optional },
1543     { 0x0091, sent|defwinproc|optional },
1544     { 0x0092, sent|defwinproc|optional },
1545     { WM_GETTEXT, sent|defwinproc|optional },
1546     { WM_ERASEBKGND, sent|optional },
1547     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1548     { 0x0093, sent|optional },
1549     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1550     { 0 }
1551 };
1552
1553 static const struct message WmSetRedrawFalseSeq[] =
1554 {
1555     { WM_SETREDRAW, sent|wparam, 0 },
1556     { 0 }
1557 };
1558
1559 static const struct message WmSetRedrawTrueSeq[] =
1560 {
1561     { WM_SETREDRAW, sent|wparam, 1 },
1562     { 0 }
1563 };
1564
1565 static const struct message WmEnableWindowSeq_1[] =
1566 {
1567     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1568     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1569     { HCBT_SETFOCUS, hook|optional },
1570     { WM_KILLFOCUS, sent|optional },
1571     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1572     { 0 }
1573 };
1574
1575 static const struct message WmEnableWindowSeq_2[] =
1576 {
1577     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1578     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1579     { 0 }
1580 };
1581
1582 static const struct message WmGetScrollRangeSeq[] =
1583 {
1584     { SBM_GETRANGE, sent },
1585     { 0 }
1586 };
1587 static const struct message WmGetScrollInfoSeq[] =
1588 {
1589     { SBM_GETSCROLLINFO, sent },
1590     { 0 }
1591 };
1592 static const struct message WmSetScrollRangeSeq[] =
1593 {
1594     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1595        sends SBM_SETSCROLLINFO.
1596      */
1597     { SBM_SETSCROLLINFO, sent },
1598     { 0 }
1599 };
1600 /* SetScrollRange for a window without a non-client area */
1601 static const struct message WmSetScrollRangeHSeq_empty[] =
1602 {
1603     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1604     { 0 }
1605 };
1606 static const struct message WmSetScrollRangeVSeq_empty[] =
1607 {
1608     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1609     { 0 }
1610 };
1611 static const struct message WmSetScrollRangeHVSeq[] =
1612 {
1613     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1614     { WM_NCCALCSIZE, sent|wparam, 1 },
1615     { WM_GETTEXT, sent|defwinproc|optional },
1616     { WM_ERASEBKGND, sent|optional },
1617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1618     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1619     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1620     { 0 }
1621 };
1622 /* SetScrollRange for a window with a non-client area */
1623 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1624 {
1625     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1626     { WM_NCCALCSIZE, sent|wparam, 1 },
1627     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1628     { WM_NCPAINT, sent|optional },
1629     { WM_STYLECHANGING, sent|defwinproc|optional },
1630     { WM_STYLECHANGED, sent|defwinproc|optional },
1631     { WM_STYLECHANGING, sent|defwinproc|optional },
1632     { WM_STYLECHANGED, sent|defwinproc|optional },
1633     { WM_STYLECHANGING, sent|defwinproc|optional },
1634     { WM_STYLECHANGED, sent|defwinproc|optional },
1635     { WM_STYLECHANGING, sent|defwinproc|optional },
1636     { WM_STYLECHANGED, sent|defwinproc|optional },
1637     { WM_GETTEXT, sent|defwinproc|optional },
1638     { WM_GETTEXT, sent|defwinproc|optional },
1639     { WM_ERASEBKGND, sent|optional },
1640     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1641     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1642     { WM_SIZE, sent|defwinproc|optional },
1643     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1644     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1645     { WM_GETTEXT, sent|optional },
1646     { WM_GETTEXT, sent|optional },
1647     { WM_GETTEXT, sent|optional },
1648     { WM_GETTEXT, sent|optional },
1649     { 0 }
1650 };
1651 /* test if we receive the right sequence of messages */
1652 /* after calling ShowWindow( SW_SHOWNA) */
1653 static const struct message WmSHOWNAChildInvisParInvis[] = {
1654     { WM_SHOWWINDOW, sent|wparam, 1 },
1655     { 0 }
1656 };
1657 static const struct message WmSHOWNAChildVisParInvis[] = {
1658     { WM_SHOWWINDOW, sent|wparam, 1 },
1659     { 0 }
1660 };
1661 static const struct message WmSHOWNAChildVisParVis[] = {
1662     { WM_SHOWWINDOW, sent|wparam, 1 },
1663     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1664     { 0 }
1665 };
1666 static const struct message WmSHOWNAChildInvisParVis[] = {
1667     { WM_SHOWWINDOW, sent|wparam, 1 },
1668     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1669     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1670     { WM_ERASEBKGND, sent|optional },
1671     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1672     { 0 }
1673 };
1674 static const struct message WmSHOWNATopVisible[] = {
1675     { WM_SHOWWINDOW, sent|wparam, 1 },
1676     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1677     { WM_NCPAINT, sent|wparam|optional, 1 },
1678     { WM_GETTEXT, sent|defwinproc|optional },
1679     { WM_ERASEBKGND, sent|optional },
1680     { WM_WINDOWPOSCHANGED, sent|optional },
1681     { 0 }
1682 };
1683 static const struct message WmSHOWNATopInvisible[] = {
1684     { WM_NOTIFYFORMAT, sent|optional },
1685     { WM_QUERYUISTATE, sent|optional },
1686     { WM_WINDOWPOSCHANGING, sent|optional },
1687     { WM_GETMINMAXINFO, sent|optional },
1688     { WM_NCCALCSIZE, sent|optional },
1689     { WM_WINDOWPOSCHANGED, sent|optional },
1690     { WM_SHOWWINDOW, sent|wparam, 1 },
1691     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1692     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1693     { WM_NCPAINT, sent|wparam|optional, 1 },
1694     { WM_GETTEXT, sent|defwinproc|optional },
1695     { WM_ERASEBKGND, sent|optional },
1696     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1697     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1698     { WM_NCPAINT, sent|wparam|optional, 1 },
1699     { WM_ERASEBKGND, sent|optional },
1700     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1701     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1702     { WM_MOVE, sent },
1703     { 0 }
1704 };
1705
1706 static int after_end_dialog, test_def_id;
1707 static int sequence_cnt, sequence_size;
1708 static struct recvd_message* sequence;
1709 static int log_all_parent_messages;
1710 static int paint_loop_done;
1711
1712 /* user32 functions */
1713 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1714 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1715 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1716 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1717 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1718 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1719 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1720 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
1721 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
1722 /* kernel32 functions */
1723 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1724
1725 static void init_procs(void)
1726 {
1727     HMODULE user32 = GetModuleHandleA("user32.dll");
1728     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1729
1730 #define GET_PROC(dll, func) \
1731     p ## func = (void*)GetProcAddress(dll, #func); \
1732     if(!p ## func) { \
1733       trace("GetProcAddress(%s) failed\n", #func); \
1734     }
1735
1736     GET_PROC(user32, GetAncestor)
1737     GET_PROC(user32, GetMenuInfo)
1738     GET_PROC(user32, NotifyWinEvent)
1739     GET_PROC(user32, SetMenuInfo)
1740     GET_PROC(user32, SetWinEventHook)
1741     GET_PROC(user32, TrackMouseEvent)
1742     GET_PROC(user32, UnhookWinEvent)
1743     GET_PROC(user32, GetMonitorInfoA)
1744     GET_PROC(user32, MonitorFromPoint)
1745
1746     GET_PROC(kernel32, GetCPInfoExA)
1747
1748 #undef GET_PROC
1749 }
1750
1751 static const char *get_winpos_flags(UINT flags)
1752 {
1753     static char buffer[300];
1754
1755     buffer[0] = 0;
1756 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1757     DUMP( SWP_SHOWWINDOW );
1758     DUMP( SWP_HIDEWINDOW );
1759     DUMP( SWP_NOACTIVATE );
1760     DUMP( SWP_FRAMECHANGED );
1761     DUMP( SWP_NOCOPYBITS );
1762     DUMP( SWP_NOOWNERZORDER );
1763     DUMP( SWP_NOSENDCHANGING );
1764     DUMP( SWP_DEFERERASE );
1765     DUMP( SWP_ASYNCWINDOWPOS );
1766     DUMP( SWP_NOZORDER );
1767     DUMP( SWP_NOREDRAW );
1768     DUMP( SWP_NOSIZE );
1769     DUMP( SWP_NOMOVE );
1770     DUMP( SWP_NOCLIENTSIZE );
1771     DUMP( SWP_NOCLIENTMOVE );
1772     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1773     return buffer + 1;
1774 #undef DUMP
1775 }
1776
1777 static BOOL ignore_message( UINT message )
1778 {
1779     /* these are always ignored */
1780     return (message >= 0xc000 ||
1781             message == WM_GETICON ||
1782             message == WM_GETOBJECT ||
1783             message == WM_TIMECHANGE ||
1784             message == WM_DISPLAYCHANGE ||
1785             message == WM_DEVICECHANGE ||
1786             message == WM_DWMNCRENDERINGCHANGED);
1787 }
1788
1789
1790 #define add_message(msg) add_message_(__LINE__,msg);
1791 static void add_message_(int line, const struct recvd_message *msg)
1792 {
1793     struct recvd_message *seq;
1794
1795     if (!sequence) 
1796     {
1797         sequence_size = 10;
1798         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1799     }
1800     if (sequence_cnt == sequence_size) 
1801     {
1802         sequence_size *= 2;
1803         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1804     }
1805     assert(sequence);
1806
1807     seq = &sequence[sequence_cnt];
1808     seq->hwnd = msg->hwnd;
1809     seq->message = msg->message;
1810     seq->flags = msg->flags;
1811     seq->wParam = msg->wParam;
1812     seq->lParam = msg->lParam;
1813     seq->line   = line;
1814     seq->descr  = msg->descr;
1815     seq->output[0] = 0;
1816
1817     if (msg->descr)
1818     {
1819         if (msg->flags & hook)
1820         {
1821             static const char * const CBT_code_name[10] =
1822             {
1823                 "HCBT_MOVESIZE",
1824                 "HCBT_MINMAX",
1825                 "HCBT_QS",
1826                 "HCBT_CREATEWND",
1827                 "HCBT_DESTROYWND",
1828                 "HCBT_ACTIVATE",
1829                 "HCBT_CLICKSKIPPED",
1830                 "HCBT_KEYSKIPPED",
1831                 "HCBT_SYSCOMMAND",
1832                 "HCBT_SETFOCUS"
1833             };
1834             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1835
1836             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1837                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1838         }
1839         else if (msg->flags & winevent_hook)
1840         {
1841             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1842                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1843         }
1844         else
1845         {
1846             switch (msg->message)
1847             {
1848             case WM_WINDOWPOSCHANGING:
1849             case WM_WINDOWPOSCHANGED:
1850             {
1851                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1852
1853                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1854                           msg->descr, msg->hwnd,
1855                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1856                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1857                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1858                           get_winpos_flags(winpos->flags) );
1859
1860                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1861                  * in the high word for internal purposes
1862                  */
1863                 seq->wParam = winpos->flags & 0xffff;
1864                 /* We are not interested in the flags that don't match under XP and Win9x */
1865                 seq->wParam &= ~SWP_NOZORDER;
1866                 break;
1867             }
1868
1869             case WM_DRAWITEM:
1870             {
1871                 DRAW_ITEM_STRUCT di;
1872                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1873
1874                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1875                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1876                          dis->itemID, dis->itemAction, dis->itemState);
1877
1878                 di.u.lp = 0;
1879                 di.u.item.type = dis->CtlType;
1880                 di.u.item.ctl_id = dis->CtlID;
1881                 if (dis->CtlType == ODT_LISTBOX ||
1882                     dis->CtlType == ODT_COMBOBOX ||
1883                     dis->CtlType == ODT_MENU)
1884                     di.u.item.item_id = dis->itemID;
1885                 di.u.item.action = dis->itemAction;
1886                 di.u.item.state = dis->itemState;
1887
1888                 seq->lParam = di.u.lp;
1889                 break;
1890             }
1891             default:
1892                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1893                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1894                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1895             }
1896             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1897                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1898         }
1899     }
1900
1901     sequence_cnt++;
1902 }
1903
1904 /* try to make sure pending X events have been processed before continuing */
1905 static void flush_events(void)
1906 {
1907     MSG msg;
1908     int diff = 200;
1909     int min_timeout = 100;
1910     DWORD time = GetTickCount() + diff;
1911
1912     while (diff > 0)
1913     {
1914         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1915         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1916         diff = time - GetTickCount();
1917     }
1918 }
1919
1920 static void flush_sequence(void)
1921 {
1922     HeapFree(GetProcessHeap(), 0, sequence);
1923     sequence = 0;
1924     sequence_cnt = sequence_size = 0;
1925 }
1926
1927 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1928 {
1929     const struct recvd_message *actual = sequence;
1930     unsigned int count = 0;
1931
1932     trace_(file, line)("Failed sequence %s:\n", context );
1933     while (expected->message && actual->message)
1934     {
1935         if (actual->output[0])
1936         {
1937             if (expected->flags & hook)
1938             {
1939                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1940                                     count, expected->message, actual->output );
1941             }
1942             else if (expected->flags & winevent_hook)
1943             {
1944                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1945                                     count, expected->message, actual->output );
1946             }
1947             else
1948             {
1949                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1950                                     count, expected->message, actual->output );
1951             }
1952         }
1953
1954         if (expected->message == actual->message)
1955         {
1956             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1957                 (expected->flags & optional))
1958             {
1959                 /* don't match messages if their defwinproc status differs */
1960                 expected++;
1961             }
1962             else
1963             {
1964                 expected++;
1965                 actual++;
1966             }
1967         }
1968         /* silently drop winevent messages if there is no support for them */
1969         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1970             expected++;
1971         else
1972         {
1973             expected++;
1974             actual++;
1975         }
1976         count++;
1977     }
1978
1979     /* optional trailing messages */
1980     while (expected->message && ((expected->flags & optional) ||
1981             ((expected->flags & winevent_hook) && !hEvent_hook)))
1982     {
1983         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1984         expected++;
1985         count++;
1986     }
1987
1988     if (expected->message)
1989     {
1990         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1991         return;
1992     }
1993
1994     while (actual->message && actual->output[0])
1995     {
1996         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
1997         actual++;
1998         count++;
1999     }
2000 }
2001
2002 #define ok_sequence( exp, contx, todo) \
2003         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2004
2005
2006 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
2007                          const char *file, int line)
2008 {
2009     static const struct recvd_message end_of_sequence;
2010     const struct message *expected = expected_list;
2011     const struct recvd_message *actual;
2012     int failcount = 0, dump = 0;
2013     unsigned int count = 0;
2014
2015     add_message(&end_of_sequence);
2016
2017     actual = sequence;
2018
2019     while (expected->message && actual->message)
2020     {
2021         if (expected->message == actual->message)
2022         {
2023             if (expected->flags & wparam)
2024             {
2025                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2026                 {
2027                     todo_wine {
2028                         failcount ++;
2029                         if (strcmp(winetest_platform, "wine")) dump++;
2030                         ok_( file, line) (FALSE,
2031                             "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2032                             context, count, expected->message, expected->wParam, actual->wParam);
2033                     }
2034                 }
2035                 else
2036                 {
2037                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2038                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2039                                      context, count, expected->message, expected->wParam, actual->wParam);
2040                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2041                 }
2042
2043             }
2044             if (expected->flags & lparam)
2045             {
2046                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2047                 {
2048                     todo_wine {
2049                         failcount ++;
2050                         if (strcmp(winetest_platform, "wine")) dump++;
2051                         ok_( file, line) (FALSE,
2052                             "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2053                             context, count, expected->message, expected->lParam, actual->lParam);
2054                     }
2055                 }
2056                 else
2057                 {
2058                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2059                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2060                                      context, count, expected->message, expected->lParam, actual->lParam);
2061                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2062                 }
2063             }
2064             if ((expected->flags & optional) &&
2065                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2066             {
2067                 /* don't match optional messages if their defwinproc or parent status differs */
2068                 expected++;
2069                 count++;
2070                 continue;
2071             }
2072             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2073             {
2074                     todo_wine {
2075                         failcount ++;
2076                         if (strcmp(winetest_platform, "wine")) dump++;
2077                         ok_( file, line) (FALSE,
2078                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2079                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2080                     }
2081             }
2082             else
2083             {
2084                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2085                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2086                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2087                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2088             }
2089
2090             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2091                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2092                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2093             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2094
2095             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2096                 "%s: %u: the msg 0x%04x should have been %s\n",
2097                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2098             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2099
2100             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2101                 "%s: %u: the msg 0x%04x was expected in %s\n",
2102                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2103             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2104
2105             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2106                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2107                 context, count, expected->message);
2108             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2109
2110             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2111                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2112                 context, count, expected->message);
2113             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2114
2115             expected++;
2116             actual++;
2117         }
2118         /* silently drop hook messages if there is no support for them */
2119         else if ((expected->flags & optional) ||
2120                  ((expected->flags & hook) && !hCBT_hook) ||
2121                  ((expected->flags & winevent_hook) && !hEvent_hook))
2122             expected++;
2123         else if (todo)
2124         {
2125             failcount++;
2126             todo_wine {
2127                 if (strcmp(winetest_platform, "wine")) dump++;
2128                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2129                                   context, count, expected->message, actual->message);
2130             }
2131             goto done;
2132         }
2133         else
2134         {
2135             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2136                               context, count, expected->message, actual->message);
2137             dump++;
2138             expected++;
2139             actual++;
2140         }
2141         count++;
2142     }
2143
2144     /* skip all optional trailing messages */
2145     while (expected->message && ((expected->flags & optional) ||
2146                                  ((expected->flags & hook) && !hCBT_hook) ||
2147                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2148         expected++;
2149
2150     if (todo)
2151     {
2152         todo_wine {
2153             if (expected->message || actual->message) {
2154                 failcount++;
2155                 if (strcmp(winetest_platform, "wine")) dump++;
2156                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2157                                   context, count, expected->message, actual->message);
2158             }
2159         }
2160     }
2161     else
2162     {
2163         if (expected->message || actual->message)
2164         {
2165             dump++;
2166             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2167                               context, count, expected->message, actual->message);
2168         }
2169     }
2170     if( todo && !failcount) /* succeeded yet marked todo */
2171         todo_wine {
2172             if (!strcmp(winetest_platform, "wine")) dump++;
2173             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2174         }
2175
2176 done:
2177     if (dump) dump_sequence(expected_list, context, file, line);
2178     flush_sequence();
2179 }
2180
2181 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2182
2183 /******************************** MDI test **********************************/
2184
2185 /* CreateWindow for MDI frame window, initially visible */
2186 static const struct message WmCreateMDIframeSeq[] = {
2187     { HCBT_CREATEWND, hook },
2188     { WM_GETMINMAXINFO, sent },
2189     { WM_NCCREATE, sent },
2190     { WM_NCCALCSIZE, sent|wparam, 0 },
2191     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2192     { WM_CREATE, sent },
2193     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2194     { WM_NOTIFYFORMAT, sent|optional },
2195     { WM_QUERYUISTATE, sent|optional },
2196     { WM_WINDOWPOSCHANGING, sent|optional },
2197     { WM_GETMINMAXINFO, sent|optional },
2198     { WM_NCCALCSIZE, sent|optional },
2199     { WM_WINDOWPOSCHANGED, sent|optional },
2200     { WM_SHOWWINDOW, sent|wparam, 1 },
2201     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2202     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2203     { HCBT_ACTIVATE, hook },
2204     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2205     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2206     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2207     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2208     { WM_NCACTIVATE, sent },
2209     { WM_GETTEXT, sent|defwinproc|optional },
2210     { WM_ACTIVATE, sent|wparam, 1 },
2211     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2212     { HCBT_SETFOCUS, hook },
2213     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2214     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2215     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2216     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2217     /* Win9x adds SWP_NOZORDER below */
2218     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2219     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2220     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2221     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2222     { WM_MOVE, sent },
2223     { 0 }
2224 };
2225 /* DestroyWindow for MDI frame window, initially visible */
2226 static const struct message WmDestroyMDIframeSeq[] = {
2227     { HCBT_DESTROYWND, hook },
2228     { 0x0090, sent|optional },
2229     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2230     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2231     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2232     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2233     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2234     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2235     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2236     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2237     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2238     { WM_DESTROY, sent },
2239     { WM_NCDESTROY, sent },
2240     { 0 }
2241 };
2242 /* CreateWindow for MDI client window, initially visible */
2243 static const struct message WmCreateMDIclientSeq[] = {
2244     { HCBT_CREATEWND, hook },
2245     { WM_NCCREATE, sent },
2246     { WM_NCCALCSIZE, sent|wparam, 0 },
2247     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2248     { WM_CREATE, sent },
2249     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2250     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2251     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2252     { WM_MOVE, sent },
2253     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2254     { WM_SHOWWINDOW, sent|wparam, 1 },
2255     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2256     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2257     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2258     { 0 }
2259 };
2260 /* ShowWindow(SW_SHOW) for MDI client window */
2261 static const struct message WmShowMDIclientSeq[] = {
2262     { WM_SHOWWINDOW, sent|wparam, 1 },
2263     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2264     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2265     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2266     { 0 }
2267 };
2268 /* ShowWindow(SW_HIDE) for MDI client window */
2269 static const struct message WmHideMDIclientSeq[] = {
2270     { WM_SHOWWINDOW, sent|wparam, 0 },
2271     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2272     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2273     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2274     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2275     { 0 }
2276 };
2277 /* DestroyWindow for MDI client window, initially visible */
2278 static const struct message WmDestroyMDIclientSeq[] = {
2279     { HCBT_DESTROYWND, hook },
2280     { 0x0090, sent|optional },
2281     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2282     { WM_SHOWWINDOW, sent|wparam, 0 },
2283     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2284     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2285     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2286     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2287     { WM_DESTROY, sent },
2288     { WM_NCDESTROY, sent },
2289     { 0 }
2290 };
2291 /* CreateWindow for MDI child window, initially visible */
2292 static const struct message WmCreateMDIchildVisibleSeq[] = {
2293     { HCBT_CREATEWND, hook },
2294     { WM_NCCREATE, sent }, 
2295     { WM_NCCALCSIZE, sent|wparam, 0 },
2296     { WM_CREATE, sent },
2297     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2298     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2299     { WM_MOVE, sent },
2300     /* Win2k sends wparam set to
2301      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2302      * while Win9x doesn't bother to set child window id according to
2303      * CLIENTCREATESTRUCT.idFirstChild
2304      */
2305     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2306     { WM_SHOWWINDOW, sent|wparam, 1 },
2307     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2308     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2309     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2310     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2311     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2312     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2313     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2314
2315     /* Win9x: message sequence terminates here. */
2316
2317     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2318     { HCBT_SETFOCUS, hook }, /* in MDI client */
2319     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2320     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2321     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2322     { WM_SETFOCUS, sent }, /* in MDI client */
2323     { HCBT_SETFOCUS, hook },
2324     { WM_KILLFOCUS, sent }, /* in MDI client */
2325     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2326     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2327     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2328     { WM_SETFOCUS, sent|defwinproc },
2329     { WM_MDIACTIVATE, sent|defwinproc },
2330     { 0 }
2331 };
2332 /* CreateWindow for MDI child window with invisible parent */
2333 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2334     { HCBT_CREATEWND, hook },
2335     { WM_GETMINMAXINFO, sent },
2336     { WM_NCCREATE, sent }, 
2337     { WM_NCCALCSIZE, sent|wparam, 0 },
2338     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2339     { WM_CREATE, sent },
2340     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2341     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2342     { WM_MOVE, sent },
2343     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2344     { WM_SHOWWINDOW, sent|wparam, 1 },
2345     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2346     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2347     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2348     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2349
2350     /* Win9x: message sequence terminates here. */
2351
2352     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2353     { HCBT_SETFOCUS, hook }, /* in MDI client */
2354     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2355     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2356     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2357     { WM_SETFOCUS, sent }, /* in MDI client */
2358     { HCBT_SETFOCUS, hook },
2359     { WM_KILLFOCUS, sent }, /* in MDI client */
2360     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2361     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2362     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2363     { WM_SETFOCUS, sent|defwinproc },
2364     { WM_MDIACTIVATE, sent|defwinproc },
2365     { 0 }
2366 };
2367 /* DestroyWindow for MDI child window, initially visible */
2368 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2369     { HCBT_DESTROYWND, hook },
2370     /* Win2k sends wparam set to
2371      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2372      * while Win9x doesn't bother to set child window id according to
2373      * CLIENTCREATESTRUCT.idFirstChild
2374      */
2375     { 0x0090, sent|optional },
2376     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2377     { WM_SHOWWINDOW, sent|wparam, 0 },
2378     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2379     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2380     { WM_ERASEBKGND, sent|parent|optional },
2381     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2382
2383     /* { WM_DESTROY, sent }
2384      * Win9x: message sequence terminates here.
2385      */
2386
2387     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2388     { WM_KILLFOCUS, sent },
2389     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2390     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2391     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2392     { WM_SETFOCUS, sent }, /* in MDI client */
2393
2394     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2395     { WM_KILLFOCUS, sent }, /* in MDI client */
2396     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2397     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2398     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2399     { WM_SETFOCUS, sent }, /* in MDI client */
2400
2401     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2402
2403     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2404     { WM_KILLFOCUS, sent },
2405     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2406     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2407     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2408     { WM_SETFOCUS, sent }, /* in MDI client */
2409
2410     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2411     { WM_KILLFOCUS, sent }, /* in MDI client */
2412     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2413     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2414     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2415     { WM_SETFOCUS, sent }, /* in MDI client */
2416
2417     { WM_DESTROY, sent },
2418
2419     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2420     { WM_KILLFOCUS, sent },
2421     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2422     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2423     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2424     { WM_SETFOCUS, sent }, /* in MDI client */
2425
2426     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2427     { WM_KILLFOCUS, sent }, /* in MDI client */
2428     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2429     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2430     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2431     { WM_SETFOCUS, sent }, /* in MDI client */
2432
2433     { WM_NCDESTROY, sent },
2434     { 0 }
2435 };
2436 /* CreateWindow for MDI child window, initially invisible */
2437 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2438     { HCBT_CREATEWND, hook },
2439     { WM_NCCREATE, sent }, 
2440     { WM_NCCALCSIZE, sent|wparam, 0 },
2441     { WM_CREATE, sent },
2442     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2443     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2444     { WM_MOVE, sent },
2445     /* Win2k sends wparam set to
2446      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2447      * while Win9x doesn't bother to set child window id according to
2448      * CLIENTCREATESTRUCT.idFirstChild
2449      */
2450     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2451     { 0 }
2452 };
2453 /* DestroyWindow for MDI child window, initially invisible */
2454 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2455     { HCBT_DESTROYWND, hook },
2456     /* Win2k sends wparam set to
2457      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2458      * while Win9x doesn't bother to set child window id according to
2459      * CLIENTCREATESTRUCT.idFirstChild
2460      */
2461     { 0x0090, sent|optional },
2462     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2463     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2464     { WM_DESTROY, sent },
2465     { WM_NCDESTROY, sent },
2466     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2467     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2468     { 0 }
2469 };
2470 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2471 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2472     { HCBT_CREATEWND, hook },
2473     { WM_NCCREATE, sent }, 
2474     { WM_NCCALCSIZE, sent|wparam, 0 },
2475     { WM_CREATE, sent },
2476     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2477     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2478     { WM_MOVE, sent },
2479     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2480     { WM_GETMINMAXINFO, sent },
2481     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2482     { WM_NCCALCSIZE, sent|wparam, 1 },
2483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2484     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2485      /* in MDI frame */
2486     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2487     { WM_NCCALCSIZE, sent|wparam, 1 },
2488     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2489     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2490     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2491     /* Win2k sends wparam set to
2492      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2493      * while Win9x doesn't bother to set child window id according to
2494      * CLIENTCREATESTRUCT.idFirstChild
2495      */
2496     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2497     { WM_SHOWWINDOW, sent|wparam, 1 },
2498     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2499     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2500     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2501     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2502     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2503     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2504     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2505
2506     /* Win9x: message sequence terminates here. */
2507
2508     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2509     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2510     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2511     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2512     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2513     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2514     { HCBT_SETFOCUS, hook|optional },
2515     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2516     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2517     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2518     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2519     { WM_SETFOCUS, sent|defwinproc|optional },
2520     { WM_MDIACTIVATE, sent|defwinproc|optional },
2521      /* in MDI frame */
2522     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2523     { WM_NCCALCSIZE, sent|wparam, 1 },
2524     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2525     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2526     { 0 }
2527 };
2528 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2529 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2530     /* restore the 1st MDI child */
2531     { WM_SETREDRAW, sent|wparam, 0 },
2532     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2533     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2534     { WM_NCCALCSIZE, sent|wparam, 1 },
2535     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2536     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2537     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2538      /* in MDI frame */
2539     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2540     { WM_NCCALCSIZE, sent|wparam, 1 },
2541     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2542     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2543     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2544     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2545     /* create the 2nd MDI child */
2546     { HCBT_CREATEWND, hook },
2547     { WM_NCCREATE, sent }, 
2548     { WM_NCCALCSIZE, sent|wparam, 0 },
2549     { WM_CREATE, sent },
2550     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2551     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2552     { WM_MOVE, sent },
2553     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2554     { WM_GETMINMAXINFO, sent },
2555     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2556     { WM_NCCALCSIZE, sent|wparam, 1 },
2557     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2558     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2559     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2560      /* in MDI frame */
2561     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2562     { WM_NCCALCSIZE, sent|wparam, 1 },
2563     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2564     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2565     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2566     /* Win2k sends wparam set to
2567      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2568      * while Win9x doesn't bother to set child window id according to
2569      * CLIENTCREATESTRUCT.idFirstChild
2570      */
2571     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2572     { WM_SHOWWINDOW, sent|wparam, 1 },
2573     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2574     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2575     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2576     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2577     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2578     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2579
2580     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2581     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2582
2583     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2584
2585     /* Win9x: message sequence terminates here. */
2586
2587     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2588     { HCBT_SETFOCUS, hook },
2589     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2590     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2591     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2592     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2593     { WM_SETFOCUS, sent }, /* in MDI client */
2594     { HCBT_SETFOCUS, hook },
2595     { WM_KILLFOCUS, sent }, /* in MDI client */
2596     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2597     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2598     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2599     { WM_SETFOCUS, sent|defwinproc },
2600
2601     { WM_MDIACTIVATE, sent|defwinproc },
2602      /* in MDI frame */
2603     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2604     { WM_NCCALCSIZE, sent|wparam, 1 },
2605     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2606     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2607     { 0 }
2608 };
2609 /* WM_MDICREATE MDI child window, initially visible and maximized */
2610 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2611     { WM_MDICREATE, sent },
2612     { HCBT_CREATEWND, hook },
2613     { WM_NCCREATE, sent }, 
2614     { WM_NCCALCSIZE, sent|wparam, 0 },
2615     { WM_CREATE, sent },
2616     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2617     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2618     { WM_MOVE, sent },
2619     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2620     { WM_GETMINMAXINFO, sent },
2621     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2622     { WM_NCCALCSIZE, sent|wparam, 1 },
2623     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2624     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2625
2626      /* in MDI frame */
2627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2628     { WM_NCCALCSIZE, sent|wparam, 1 },
2629     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2630     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2631     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2632
2633     /* Win2k sends wparam set to
2634      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2635      * while Win9x doesn't bother to set child window id according to
2636      * CLIENTCREATESTRUCT.idFirstChild
2637      */
2638     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2639     { WM_SHOWWINDOW, sent|wparam, 1 },
2640     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2641
2642     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2643
2644     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2645     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2646     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2647
2648     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2649     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2650
2651     /* Win9x: message sequence terminates here. */
2652
2653     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2654     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2655     { HCBT_SETFOCUS, hook }, /* in MDI client */
2656     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2657     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2658     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2659     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2660     { HCBT_SETFOCUS, hook|optional },
2661     { WM_KILLFOCUS, sent }, /* in MDI client */
2662     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2663     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2664     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2665     { WM_SETFOCUS, sent|defwinproc },
2666
2667     { WM_MDIACTIVATE, sent|defwinproc },
2668
2669      /* in MDI child */
2670     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2671     { WM_NCCALCSIZE, sent|wparam, 1 },
2672     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2673     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2674
2675      /* in MDI frame */
2676     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2677     { WM_NCCALCSIZE, sent|wparam, 1 },
2678     { 0x0093, sent|defwinproc|optional },
2679     { 0x0093, sent|defwinproc|optional },
2680     { 0x0093, sent|defwinproc|optional },
2681     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2682     { WM_MOVE, sent|defwinproc },
2683     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2684
2685      /* in MDI client */
2686     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2687     { WM_NCCALCSIZE, sent|wparam, 1 },
2688     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2689     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2690
2691      /* in MDI child */
2692     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2693     { WM_NCCALCSIZE, sent|wparam, 1 },
2694     { 0x0093, sent|optional },
2695     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2696     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2697
2698     { 0x0093, sent|optional },
2699     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2700     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2701     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2702     { 0x0093, sent|defwinproc|optional },
2703     { 0x0093, sent|defwinproc|optional },
2704     { 0x0093, sent|defwinproc|optional },
2705     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2706     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2707
2708     { 0 }
2709 };
2710 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2711 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2712     { HCBT_CREATEWND, hook },
2713     { WM_GETMINMAXINFO, sent },
2714     { WM_NCCREATE, sent }, 
2715     { WM_NCCALCSIZE, sent|wparam, 0 },
2716     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2717     { WM_CREATE, sent },
2718     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2719     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2720     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2721     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2722     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2723     { WM_MOVE, sent },
2724     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2725     { WM_GETMINMAXINFO, sent },
2726     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2727     { WM_GETMINMAXINFO, sent|defwinproc },
2728     { WM_NCCALCSIZE, sent|wparam, 1 },
2729     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2730     { WM_MOVE, sent|defwinproc },
2731     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2732      /* in MDI frame */
2733     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2734     { WM_NCCALCSIZE, sent|wparam, 1 },
2735     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2736     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2737     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2738     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2739     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2740     /* Win2k sends wparam set to
2741      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2742      * while Win9x doesn't bother to set child window id according to
2743      * CLIENTCREATESTRUCT.idFirstChild
2744      */
2745     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2746     { 0 }
2747 };
2748 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2749 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2750     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2751     { HCBT_SYSCOMMAND, hook },
2752     { WM_CLOSE, sent|defwinproc },
2753     { WM_MDIDESTROY, sent }, /* in MDI client */
2754
2755     /* bring the 1st MDI child to top */
2756     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2757     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2758
2759     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2760
2761     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2762     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2763     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2764
2765     /* maximize the 1st MDI child */
2766     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2767     { WM_GETMINMAXINFO, sent|defwinproc },
2768     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2769     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2770     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2771     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2772     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2773
2774     /* restore the 2nd MDI child */
2775     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2776     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2777     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2778     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2779
2780     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2781
2782     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2783     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2784
2785     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2786
2787     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2788      /* in MDI frame */
2789     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2790     { WM_NCCALCSIZE, sent|wparam, 1 },
2791     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2792     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2793     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2794
2795     /* bring the 1st MDI child to top */
2796     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2797     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2798     { HCBT_SETFOCUS, hook },
2799     { WM_KILLFOCUS, sent|defwinproc },
2800     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2801     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2802     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2803     { WM_SETFOCUS, sent }, /* in MDI client */
2804     { HCBT_SETFOCUS, hook },
2805     { WM_KILLFOCUS, sent }, /* in MDI client */
2806     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2807     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2808     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2809     { WM_SETFOCUS, sent|defwinproc },
2810     { WM_MDIACTIVATE, sent|defwinproc },
2811     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2812
2813     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2814     { WM_SHOWWINDOW, sent|wparam, 1 },
2815     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2816     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2817     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2818     { WM_MDIREFRESHMENU, sent },
2819
2820     { HCBT_DESTROYWND, hook },
2821     /* Win2k sends wparam set to
2822      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2823      * while Win9x doesn't bother to set child window id according to
2824      * CLIENTCREATESTRUCT.idFirstChild
2825      */
2826     { 0x0090, sent|defwinproc|optional },
2827     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2828     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2829     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2830     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2831     { WM_ERASEBKGND, sent|parent|optional },
2832     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2833
2834     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2835     { WM_DESTROY, sent|defwinproc },
2836     { WM_NCDESTROY, sent|defwinproc },
2837     { 0 }
2838 };
2839 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2840 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2841     { WM_MDIDESTROY, sent }, /* in MDI client */
2842     { WM_SHOWWINDOW, sent|wparam, 0 },
2843     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2844     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2845     { WM_ERASEBKGND, sent|parent|optional },
2846     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2847
2848     { HCBT_SETFOCUS, hook },
2849     { WM_KILLFOCUS, sent },
2850     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2851     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2852     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2853     { WM_SETFOCUS, sent }, /* in MDI client */
2854     { HCBT_SETFOCUS, hook },
2855     { WM_KILLFOCUS, sent }, /* in MDI client */
2856     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2857     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2858     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2859     { WM_SETFOCUS, sent },
2860
2861      /* in MDI child */
2862     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2863     { WM_NCCALCSIZE, sent|wparam, 1 },
2864     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2865     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2866
2867      /* in MDI frame */
2868     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2869     { WM_NCCALCSIZE, sent|wparam, 1 },
2870     { 0x0093, sent|defwinproc|optional },
2871     { 0x0093, sent|defwinproc|optional },
2872     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2873     { WM_MOVE, sent|defwinproc },
2874     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2875
2876      /* in MDI client */
2877     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2878     { WM_NCCALCSIZE, sent|wparam, 1 },
2879     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2880     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2881
2882      /* in MDI child */
2883     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2884     { WM_NCCALCSIZE, sent|wparam, 1 },
2885     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2886     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2887
2888      /* in MDI child */
2889     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2890     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2891     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2892     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2893
2894      /* in MDI frame */
2895     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2896     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2897     { 0x0093, sent|defwinproc|optional },
2898     { 0x0093, sent|defwinproc|optional },
2899     { 0x0093, sent|defwinproc|optional },
2900     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2901     { WM_MOVE, sent|defwinproc },
2902     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2903
2904      /* in MDI client */
2905     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2906     { WM_NCCALCSIZE, sent|wparam, 1 },
2907     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2908     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2909
2910      /* in MDI child */
2911     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2912     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2913     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2914     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2915     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2916     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2917
2918     { 0x0093, sent|defwinproc|optional },
2919     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2920     { 0x0093, sent|defwinproc|optional },
2921     { 0x0093, sent|defwinproc|optional },
2922     { 0x0093, sent|defwinproc|optional },
2923     { 0x0093, sent|optional },
2924
2925     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2926     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2927     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2928     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2929     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2930
2931      /* in MDI frame */
2932     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2933     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2934     { 0x0093, sent|defwinproc|optional },
2935     { 0x0093, sent|defwinproc|optional },
2936     { 0x0093, sent|defwinproc|optional },
2937     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2938     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2939     { 0x0093, sent|optional },
2940
2941     { WM_NCACTIVATE, sent|wparam, 0 },
2942     { WM_MDIACTIVATE, sent },
2943
2944     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2945     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2946     { WM_NCCALCSIZE, sent|wparam, 1 },
2947
2948     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2949
2950     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2951     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2952     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2953
2954      /* in MDI child */
2955     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2956     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2957     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2958     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2959
2960      /* in MDI frame */
2961     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2962     { WM_NCCALCSIZE, sent|wparam, 1 },
2963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2964     { WM_MOVE, sent|defwinproc },
2965     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2966
2967      /* in MDI client */
2968     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2969     { WM_NCCALCSIZE, sent|wparam, 1 },
2970     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2971     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2972     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2973     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2974     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2975     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2976     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2977
2978     { HCBT_SETFOCUS, hook },
2979     { WM_KILLFOCUS, sent },
2980     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2981     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2982     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2983     { WM_SETFOCUS, sent }, /* in MDI client */
2984
2985     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2986
2987     { HCBT_DESTROYWND, hook },
2988     /* Win2k sends wparam set to
2989      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2990      * while Win9x doesn't bother to set child window id according to
2991      * CLIENTCREATESTRUCT.idFirstChild
2992      */
2993     { 0x0090, sent|optional },
2994     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2995
2996     { WM_SHOWWINDOW, sent|wparam, 0 },
2997     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2998     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2999     { WM_ERASEBKGND, sent|parent|optional },
3000     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3001
3002     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3003     { WM_DESTROY, sent },
3004     { WM_NCDESTROY, sent },
3005     { 0 }
3006 };
3007 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3008 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3009     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3010     { WM_GETMINMAXINFO, sent },
3011     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3012     { WM_NCCALCSIZE, sent|wparam, 1 },
3013     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3014     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3015
3016     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3017     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3018     { HCBT_SETFOCUS, hook|optional },
3019     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3020     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3021     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3022     { HCBT_SETFOCUS, hook|optional },
3023     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3024     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3025     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3026     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3027     { WM_SETFOCUS, sent|optional|defwinproc },
3028     { WM_MDIACTIVATE, sent|optional|defwinproc },
3029     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3030     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3031      /* in MDI frame */
3032     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3033     { WM_NCCALCSIZE, sent|wparam, 1 },
3034     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3035     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3036     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3037     { 0 }
3038 };
3039 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3040 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3041     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3042     { WM_GETMINMAXINFO, sent },
3043     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3044     { WM_GETMINMAXINFO, sent|defwinproc },
3045     { WM_NCCALCSIZE, sent|wparam, 1 },
3046     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3047     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3048
3049     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3050     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3051     { HCBT_SETFOCUS, hook|optional },
3052     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3053     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3054     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3055     { HCBT_SETFOCUS, hook|optional },
3056     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3057     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3058     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3059     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3060     { WM_SETFOCUS, sent|defwinproc|optional },
3061     { WM_MDIACTIVATE, sent|defwinproc|optional },
3062     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3063     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3064     { 0 }
3065 };
3066 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3067 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3068     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3069     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3070     { WM_GETMINMAXINFO, sent },
3071     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3072     { WM_GETMINMAXINFO, sent|defwinproc },
3073     { WM_NCCALCSIZE, sent|wparam, 1 },
3074     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3075     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3076     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3077     { WM_MOVE, sent|defwinproc },
3078     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3079
3080     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3081     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3082     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3083     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3084     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3085     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3086      /* in MDI frame */
3087     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3088     { WM_NCCALCSIZE, sent|wparam, 1 },
3089     { 0x0093, sent|defwinproc|optional },
3090     { 0x0094, sent|defwinproc|optional },
3091     { 0x0094, sent|defwinproc|optional },
3092     { 0x0094, sent|defwinproc|optional },
3093     { 0x0094, sent|defwinproc|optional },
3094     { 0x0093, sent|defwinproc|optional },
3095     { 0x0093, sent|defwinproc|optional },
3096     { 0x0091, sent|defwinproc|optional },
3097     { 0x0092, sent|defwinproc|optional },
3098     { 0x0092, sent|defwinproc|optional },
3099     { 0x0092, sent|defwinproc|optional },
3100     { 0x0092, sent|defwinproc|optional },
3101     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3102     { WM_MOVE, sent|defwinproc },
3103     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3104     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3105      /* in MDI client */
3106     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3107     { WM_NCCALCSIZE, sent|wparam, 1 },
3108     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3109     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3110      /* in MDI child */
3111     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3112     { WM_GETMINMAXINFO, sent|defwinproc },
3113     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3114     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3115     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3116     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3117     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3118     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3119     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3120     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3121      /* in MDI frame */
3122     { 0x0093, sent|optional },
3123     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3124     { 0x0093, sent|defwinproc|optional },
3125     { 0x0093, sent|defwinproc|optional },
3126     { 0x0093, sent|defwinproc|optional },
3127     { 0x0091, sent|defwinproc|optional },
3128     { 0x0092, sent|defwinproc|optional },
3129     { 0x0092, sent|defwinproc|optional },
3130     { 0x0092, sent|defwinproc|optional },
3131     { 0x0092, sent|defwinproc|optional },
3132     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3133     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3134     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3135     { 0 }
3136 };
3137 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3138 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3139     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3140     { WM_GETMINMAXINFO, sent },
3141     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3142     { WM_NCCALCSIZE, sent|wparam, 1 },
3143     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3144     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3145     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3146      /* in MDI frame */
3147     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3148     { WM_NCCALCSIZE, sent|wparam, 1 },
3149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3150     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3151     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3152     { 0 }
3153 };
3154 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3155 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3156     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3157     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3158     { WM_NCCALCSIZE, sent|wparam, 1 },
3159     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3160     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3161     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3162      /* in MDI frame */
3163     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3164     { WM_NCCALCSIZE, sent|wparam, 1 },
3165     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3166     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3167     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3168     { 0 }
3169 };
3170 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3171 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3172     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3173     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3174     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3175     { WM_NCCALCSIZE, sent|wparam, 1 },
3176     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3178     { WM_MOVE, sent|defwinproc },
3179     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3180     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3181     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3182     { HCBT_SETFOCUS, hook },
3183     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3184     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3185     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3186     { WM_SETFOCUS, sent },
3187     { 0 }
3188 };
3189 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3190 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3191     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3192     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3193     { WM_NCCALCSIZE, sent|wparam, 1 },
3194     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3195     { WM_MOVE, sent|defwinproc },
3196     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3197     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3198     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3199     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3200     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3201     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3202     { 0 }
3203 };
3204 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3205 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3206     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3207     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3208     { WM_NCCALCSIZE, sent|wparam, 1 },
3209     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3210     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3211     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3212     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3213      /* in MDI frame */
3214     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3215     { WM_NCCALCSIZE, sent|wparam, 1 },
3216     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3217     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3218     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3219     { 0 }
3220 };
3221
3222 static HWND mdi_client;
3223 static WNDPROC old_mdi_client_proc;
3224
3225 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3226 {
3227     struct recvd_message msg;
3228
3229     /* do not log painting messages */
3230     if (message != WM_PAINT &&
3231         message != WM_NCPAINT &&
3232         message != WM_SYNCPAINT &&
3233         message != WM_ERASEBKGND &&
3234         message != WM_NCHITTEST &&
3235         message != WM_GETTEXT &&
3236         message != WM_MDIGETACTIVE &&
3237         !ignore_message( message ))
3238     {
3239         msg.hwnd = hwnd;
3240         msg.message = message;
3241         msg.flags = sent|wparam|lparam;
3242         msg.wParam = wParam;
3243         msg.lParam = lParam;
3244         msg.descr = "mdi client";
3245         add_message(&msg);
3246     }
3247
3248     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3249 }
3250
3251 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3252 {
3253     static LONG defwndproc_counter = 0;
3254     LRESULT ret;
3255     struct recvd_message msg;
3256
3257     /* do not log painting messages */
3258     if (message != WM_PAINT &&
3259         message != WM_NCPAINT &&
3260         message != WM_SYNCPAINT &&
3261         message != WM_ERASEBKGND &&
3262         message != WM_NCHITTEST &&
3263         message != WM_GETTEXT &&
3264         !ignore_message( message ))
3265     {
3266         switch (message)
3267         {
3268             case WM_MDIACTIVATE:
3269             {
3270                 HWND active, client = GetParent(hwnd);
3271
3272                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3273
3274                 if (hwnd == (HWND)lParam) /* if we are being activated */
3275                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3276                 else
3277                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3278                 break;
3279             }
3280         }
3281
3282         msg.hwnd = hwnd;
3283         msg.message = message;
3284         msg.flags = sent|wparam|lparam;
3285         if (defwndproc_counter) msg.flags |= defwinproc;
3286         msg.wParam = wParam;
3287         msg.lParam = lParam;
3288         msg.descr = "mdi child";
3289         add_message(&msg);
3290     }
3291
3292     defwndproc_counter++;
3293     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3294     defwndproc_counter--;
3295
3296     return ret;
3297 }
3298
3299 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3300 {
3301     static LONG defwndproc_counter = 0;
3302     LRESULT ret;
3303     struct recvd_message msg;
3304
3305     /* do not log painting messages */
3306     if (message != WM_PAINT &&
3307         message != WM_NCPAINT &&
3308         message != WM_SYNCPAINT &&
3309         message != WM_ERASEBKGND &&
3310         message != WM_NCHITTEST &&
3311         message != WM_GETTEXT &&
3312         !ignore_message( message ))
3313     {
3314         msg.hwnd = hwnd;
3315         msg.message = message;
3316         msg.flags = sent|wparam|lparam;
3317         if (defwndproc_counter) msg.flags |= defwinproc;
3318         msg.wParam = wParam;
3319         msg.lParam = lParam;
3320         msg.descr = "mdi frame";
3321         add_message(&msg);
3322     }
3323
3324     defwndproc_counter++;
3325     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3326     defwndproc_counter--;
3327
3328     return ret;
3329 }
3330
3331 static BOOL mdi_RegisterWindowClasses(void)
3332 {
3333     WNDCLASSA cls;
3334
3335     cls.style = 0;
3336     cls.lpfnWndProc = mdi_frame_wnd_proc;
3337     cls.cbClsExtra = 0;
3338     cls.cbWndExtra = 0;
3339     cls.hInstance = GetModuleHandleA(0);
3340     cls.hIcon = 0;
3341     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3342     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3343     cls.lpszMenuName = NULL;
3344     cls.lpszClassName = "MDI_frame_class";
3345     if (!RegisterClassA(&cls)) return FALSE;
3346
3347     cls.lpfnWndProc = mdi_child_wnd_proc;
3348     cls.lpszClassName = "MDI_child_class";
3349     if (!RegisterClassA(&cls)) return FALSE;
3350
3351     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3352     old_mdi_client_proc = cls.lpfnWndProc;
3353     cls.hInstance = GetModuleHandleA(0);
3354     cls.lpfnWndProc = mdi_client_hook_proc;
3355     cls.lpszClassName = "MDI_client_class";
3356     if (!RegisterClassA(&cls)) assert(0);
3357
3358     return TRUE;
3359 }
3360
3361 static void test_mdi_messages(void)
3362 {
3363     MDICREATESTRUCTA mdi_cs;
3364     CLIENTCREATESTRUCT client_cs;
3365     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3366     BOOL zoomed;
3367     RECT rc;
3368     HMENU hMenu = CreateMenu();
3369
3370     assert(mdi_RegisterWindowClasses());
3371
3372     flush_sequence();
3373
3374     trace("creating MDI frame window\n");
3375     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3376                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3377                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3378                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3379                                 GetDesktopWindow(), hMenu,
3380                                 GetModuleHandleA(0), NULL);
3381     assert(mdi_frame);
3382     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3383
3384     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3385     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3386
3387     trace("creating MDI client window\n");
3388     GetClientRect(mdi_frame, &rc);
3389     client_cs.hWindowMenu = 0;
3390     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3391     mdi_client = CreateWindowExA(0, "MDI_client_class",
3392                                  NULL,
3393                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3394                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3395                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3396     assert(mdi_client);
3397     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3398
3399     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3400     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3401
3402     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3403     ok(!active_child, "wrong active MDI child %p\n", active_child);
3404     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3405
3406     SetFocus(0);
3407     flush_sequence();
3408
3409     trace("creating invisible MDI child window\n");
3410     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3411                                 WS_CHILD,
3412                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3413                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3414     assert(mdi_child);
3415
3416     flush_sequence();
3417     ShowWindow(mdi_child, SW_SHOWNORMAL);
3418     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3419
3420     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3421     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3422
3423     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3424     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3425
3426     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3427     ok(!active_child, "wrong active MDI child %p\n", active_child);
3428     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3429
3430     ShowWindow(mdi_child, SW_HIDE);
3431     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3432     flush_sequence();
3433
3434     ShowWindow(mdi_child, SW_SHOW);
3435     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3436
3437     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3438     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3439
3440     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3441     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3442
3443     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3444     ok(!active_child, "wrong active MDI child %p\n", active_child);
3445     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3446
3447     DestroyWindow(mdi_child);
3448     flush_sequence();
3449
3450     trace("creating visible MDI child window\n");
3451     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3452                                 WS_CHILD | WS_VISIBLE,
3453                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3454                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3455     assert(mdi_child);
3456     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3457
3458     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3459     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3460
3461     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3462     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3463
3464     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3465     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3466     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3467     flush_sequence();
3468
3469     DestroyWindow(mdi_child);
3470     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3471
3472     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3473     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3474
3475     /* Win2k: MDI client still returns a just destroyed child as active
3476      * Win9x: MDI client returns 0
3477      */
3478     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3479     ok(active_child == mdi_child || /* win2k */
3480        !active_child, /* win9x */
3481        "wrong active MDI child %p\n", active_child);
3482     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3483
3484     flush_sequence();
3485
3486     trace("creating invisible MDI child window\n");
3487     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3488                                 WS_CHILD,
3489                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3490                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3491     assert(mdi_child2);
3492     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3493
3494     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3495     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3496
3497     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3498     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3499
3500     /* Win2k: MDI client still returns a just destroyed child as active
3501      * Win9x: MDI client returns mdi_child2
3502      */
3503     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3504     ok(active_child == mdi_child || /* win2k */
3505        active_child == mdi_child2, /* win9x */
3506        "wrong active MDI child %p\n", active_child);
3507     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3508     flush_sequence();
3509
3510     ShowWindow(mdi_child2, SW_MAXIMIZE);
3511     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3512
3513     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3514     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3515
3516     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3517     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3518     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3519     flush_sequence();
3520
3521     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3522     ok(GetFocus() == mdi_child2 || /* win2k */
3523        GetFocus() == 0, /* win9x */
3524        "wrong focus window %p\n", GetFocus());
3525
3526     SetFocus(0);
3527     flush_sequence();
3528
3529     ShowWindow(mdi_child2, SW_HIDE);
3530     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3531
3532     ShowWindow(mdi_child2, SW_RESTORE);
3533     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3534     flush_sequence();
3535
3536     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3537     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3538
3539     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3540     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3541     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3542     flush_sequence();
3543
3544     SetFocus(0);
3545     flush_sequence();
3546
3547     ShowWindow(mdi_child2, SW_HIDE);
3548     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3549
3550     ShowWindow(mdi_child2, SW_SHOW);
3551     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3552
3553     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3554     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3555
3556     ShowWindow(mdi_child2, SW_MAXIMIZE);
3557     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3558
3559     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3560     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3561
3562     ShowWindow(mdi_child2, SW_RESTORE);
3563     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3564
3565     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3566     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3567
3568     ShowWindow(mdi_child2, SW_MINIMIZE);
3569     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3570
3571     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3572     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3573
3574     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3575     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3576     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3577     flush_sequence();
3578
3579     ShowWindow(mdi_child2, SW_RESTORE);
3580     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3581
3582     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3583     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3584
3585     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3586     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3587     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3588     flush_sequence();
3589
3590     SetFocus(0);
3591     flush_sequence();
3592
3593     ShowWindow(mdi_child2, SW_HIDE);
3594     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3595
3596     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3597     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3598
3599     DestroyWindow(mdi_child2);
3600     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3601
3602     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3603     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3604
3605     /* test for maximized MDI children */
3606     trace("creating maximized visible MDI child window 1\n");
3607     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3608                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3609                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3610                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3611     assert(mdi_child);
3612     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3613     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3614
3615     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3616     ok(GetFocus() == mdi_child || /* win2k */
3617        GetFocus() == 0, /* win9x */
3618        "wrong focus window %p\n", GetFocus());
3619
3620     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3621     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3622     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3623     flush_sequence();
3624
3625     trace("creating maximized visible MDI child window 2\n");
3626     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3627                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3628                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3629                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3630     assert(mdi_child2);
3631     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3632     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3633     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3634
3635     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3636     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3637
3638     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3639     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3640     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3641     flush_sequence();
3642
3643     trace("destroying maximized visible MDI child window 2\n");
3644     DestroyWindow(mdi_child2);
3645     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3646
3647     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3648
3649     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3650     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3651
3652     /* Win2k: MDI client still returns a just destroyed child as active
3653      * Win9x: MDI client returns 0
3654      */
3655     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3656     ok(active_child == mdi_child2 || /* win2k */
3657        !active_child, /* win9x */
3658        "wrong active MDI child %p\n", active_child);
3659     flush_sequence();
3660
3661     ShowWindow(mdi_child, SW_MAXIMIZE);
3662     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3663     flush_sequence();
3664
3665     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3666     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3667
3668     trace("re-creating maximized visible MDI child window 2\n");
3669     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3670                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3671                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3672                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3673     assert(mdi_child2);
3674     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3675     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3676     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3677
3678     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3679     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3680
3681     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3682     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3683     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3684     flush_sequence();
3685
3686     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3687     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3688     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3689
3690     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3691     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3692     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3693
3694     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3695     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3696     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3697     flush_sequence();
3698
3699     DestroyWindow(mdi_child);
3700     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3701
3702     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3703     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
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, /* win9x */
3711        "wrong active MDI child %p\n", active_child);
3712     flush_sequence();
3713
3714     trace("creating maximized invisible MDI child window\n");
3715     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3716                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3717                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3718                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3719     assert(mdi_child2);
3720     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3721     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3722     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3723     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3724
3725     /* Win2k: MDI client still returns a just destroyed child as active
3726      * Win9x: MDI client returns 0
3727      */
3728     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3729     ok(active_child == mdi_child || /* win2k */
3730        !active_child || active_child == mdi_child2, /* win9x */
3731        "wrong active MDI child %p\n", active_child);
3732     flush_sequence();
3733
3734     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3735     ShowWindow(mdi_child2, SW_MAXIMIZE);
3736     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3737     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3738     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3739     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3740
3741     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3742     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3743     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3744     flush_sequence();
3745
3746     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3747     flush_sequence();
3748
3749     /* end of test for maximized MDI children */
3750     SetFocus(0);
3751     flush_sequence();
3752     trace("creating maximized visible MDI child window 1(Switch test)\n");
3753     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3754                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3755                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3756                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3757     assert(mdi_child);
3758     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3759     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3760
3761     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3762     ok(GetFocus() == mdi_child || /* win2k */
3763        GetFocus() == 0, /* win9x */
3764        "wrong focus window %p(Switch test)\n", GetFocus());
3765
3766     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3767     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3768     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3769     flush_sequence();
3770
3771     trace("creating maximized visible MDI child window 2(Switch test)\n");
3772     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3773                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3774                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3775                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3776     assert(mdi_child2);
3777     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3778
3779     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3780     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3781
3782     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3783     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3784
3785     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3786     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3787     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3788     flush_sequence();
3789
3790     trace("Switch child window.\n");
3791     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3792     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3793     trace("end of test for switch maximized MDI children\n");
3794     flush_sequence();
3795
3796     /* Prepare for switching test of not maximized MDI children  */
3797     ShowWindow( mdi_child, SW_NORMAL );
3798     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3799     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3800     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3801     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3802     flush_sequence();
3803
3804     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3805     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3806     trace("end of test for switch not maximized MDI children\n");
3807     flush_sequence();
3808
3809     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3810     flush_sequence();
3811
3812     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3813     flush_sequence();
3814
3815     SetFocus(0);
3816     flush_sequence();
3817     /* end of tests for switch maximized/not maximized MDI children */
3818
3819     mdi_cs.szClass = "MDI_child_Class";
3820     mdi_cs.szTitle = "MDI child";
3821     mdi_cs.hOwner = GetModuleHandleA(0);
3822     mdi_cs.x = 0;
3823     mdi_cs.y = 0;
3824     mdi_cs.cx = CW_USEDEFAULT;
3825     mdi_cs.cy = CW_USEDEFAULT;
3826     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3827     mdi_cs.lParam = 0;
3828     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3829     ok(mdi_child != 0, "MDI child creation failed\n");
3830     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3831
3832     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3833
3834     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3835     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3836
3837     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3838     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3839     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3840
3841     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3842     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3843     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3844     flush_sequence();
3845
3846     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3847     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3848
3849     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3850     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3851     ok(!active_child, "wrong active MDI child %p\n", active_child);
3852
3853     SetFocus(0);
3854     flush_sequence();
3855
3856     DestroyWindow(mdi_client);
3857     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3858
3859     /* test maximization of MDI child with invisible parent */
3860     client_cs.hWindowMenu = 0;
3861     mdi_client = CreateWindow("MDI_client_class",
3862                                  NULL,
3863                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3864                                  0, 0, 660, 430,
3865                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3866     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3867
3868     ShowWindow(mdi_client, SW_HIDE);
3869     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3870
3871     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3872                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3873                                 0, 0, 650, 440,
3874                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3875     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3876
3877     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3878     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3879     zoomed = IsZoomed(mdi_child);
3880     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3881     
3882     ShowWindow(mdi_client, SW_SHOW);
3883     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3884
3885     DestroyWindow(mdi_child);
3886     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3887
3888     /* end of test for maximization of MDI child with invisible parent */
3889
3890     DestroyWindow(mdi_client);
3891     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3892
3893     DestroyWindow(mdi_frame);
3894     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3895 }
3896 /************************* End of MDI test **********************************/
3897
3898 static void test_WM_SETREDRAW(HWND hwnd)
3899 {
3900     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3901
3902     flush_events();
3903     flush_sequence();
3904
3905     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3906     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3907
3908     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3909     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3910
3911     flush_sequence();
3912     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3913     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3914
3915     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3916     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3917
3918     /* restore original WS_VISIBLE state */
3919     SetWindowLongA(hwnd, GWL_STYLE, style);
3920
3921     flush_events();
3922     flush_sequence();
3923 }
3924
3925 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3926 {
3927     struct recvd_message msg;
3928
3929     if (ignore_message( message )) return 0;
3930
3931     switch (message)
3932     {
3933         /* ignore */
3934         case WM_MOUSEMOVE:
3935         case WM_NCMOUSEMOVE:
3936         case WM_NCMOUSELEAVE:
3937         case WM_SETCURSOR:
3938             return 0;
3939         case WM_NCHITTEST:
3940             return HTCLIENT;
3941     }
3942
3943     msg.hwnd = hwnd;
3944     msg.message = message;
3945     msg.flags = sent|wparam|lparam;
3946     msg.wParam = wParam;
3947     msg.lParam = lParam;
3948     msg.descr = "dialog";
3949     add_message(&msg);
3950
3951     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3952     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3953     return 0;
3954 }
3955
3956 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3957 {
3958     DWORD style, exstyle;
3959     INT xmin, xmax;
3960     BOOL ret;
3961
3962     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3963     style = GetWindowLongA(hwnd, GWL_STYLE);
3964     /* do not be confused by WS_DLGFRAME set */
3965     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3966
3967     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3968     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3969
3970     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3971     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3972     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3973         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3974     else
3975         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3976
3977     style = GetWindowLongA(hwnd, GWL_STYLE);
3978     if (set) ok(style & set, "style %08x should be set\n", set);
3979     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3980
3981     /* a subsequent call should do nothing */
3982     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3983     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3984     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3985
3986     xmin = 0xdeadbeef;
3987     xmax = 0xdeadbeef;
3988     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3989     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3990     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3991     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3992     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3993 }
3994
3995 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3996 {
3997     DWORD style, exstyle;
3998     SCROLLINFO si;
3999     BOOL ret;
4000
4001     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4002     style = GetWindowLongA(hwnd, GWL_STYLE);
4003     /* do not be confused by WS_DLGFRAME set */
4004     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4005
4006     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4007     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4008
4009     si.cbSize = sizeof(si);
4010     si.fMask = SIF_RANGE;
4011     si.nMin = min;
4012     si.nMax = max;
4013     SetScrollInfo(hwnd, ctl, &si, TRUE);
4014     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4015         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4016     else
4017         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4018
4019     style = GetWindowLongA(hwnd, GWL_STYLE);
4020     if (set) ok(style & set, "style %08x should be set\n", set);
4021     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4022
4023     /* a subsequent call should do nothing */
4024     SetScrollInfo(hwnd, ctl, &si, TRUE);
4025     if (style & WS_HSCROLL)
4026         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4027     else if (style & WS_VSCROLL)
4028         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4029     else
4030         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4031
4032     si.fMask = SIF_PAGE;
4033     si.nPage = 5;
4034     SetScrollInfo(hwnd, ctl, &si, FALSE);
4035     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4036
4037     si.fMask = SIF_POS;
4038     si.nPos = max - 1;
4039     SetScrollInfo(hwnd, ctl, &si, FALSE);
4040     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4041
4042     si.fMask = SIF_RANGE;
4043     si.nMin = 0xdeadbeef;
4044     si.nMax = 0xdeadbeef;
4045     ret = GetScrollInfo(hwnd, ctl, &si);
4046     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4047     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4048     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4049     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4050 }
4051
4052 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4053 static void test_scroll_messages(HWND hwnd)
4054 {
4055     SCROLLINFO si;
4056     INT min, max;
4057     BOOL ret;
4058
4059     flush_events();
4060     flush_sequence();
4061
4062     min = 0xdeadbeef;
4063     max = 0xdeadbeef;
4064     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4065     ok( ret, "GetScrollRange error %d\n", GetLastError());
4066     if (sequence->message != WmGetScrollRangeSeq[0].message)
4067         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4068     /* values of min and max are undefined */
4069     flush_sequence();
4070
4071     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4072     ok( ret, "SetScrollRange error %d\n", GetLastError());
4073     if (sequence->message != WmSetScrollRangeSeq[0].message)
4074         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4075     flush_sequence();
4076
4077     min = 0xdeadbeef;
4078     max = 0xdeadbeef;
4079     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4080     ok( ret, "GetScrollRange error %d\n", GetLastError());
4081     if (sequence->message != WmGetScrollRangeSeq[0].message)
4082         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4083     /* values of min and max are undefined */
4084     flush_sequence();
4085
4086     si.cbSize = sizeof(si);
4087     si.fMask = SIF_RANGE;
4088     si.nMin = 20;
4089     si.nMax = 160;
4090     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4091     if (sequence->message != WmSetScrollRangeSeq[0].message)
4092         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4093     flush_sequence();
4094
4095     si.fMask = SIF_PAGE;
4096     si.nPage = 10;
4097     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4098     if (sequence->message != WmSetScrollRangeSeq[0].message)
4099         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4100     flush_sequence();
4101
4102     si.fMask = SIF_POS;
4103     si.nPos = 20;
4104     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4105     if (sequence->message != WmSetScrollRangeSeq[0].message)
4106         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4107     flush_sequence();
4108
4109     si.fMask = SIF_RANGE;
4110     si.nMin = 0xdeadbeef;
4111     si.nMax = 0xdeadbeef;
4112     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4113     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4114     if (sequence->message != WmGetScrollInfoSeq[0].message)
4115         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4116     /* values of min and max are undefined */
4117     flush_sequence();
4118
4119     /* set WS_HSCROLL */
4120     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4121     /* clear WS_HSCROLL */
4122     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4123
4124     /* set WS_HSCROLL */
4125     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4126     /* clear WS_HSCROLL */
4127     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4128
4129     /* set WS_VSCROLL */
4130     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4131     /* clear WS_VSCROLL */
4132     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4133
4134     /* set WS_VSCROLL */
4135     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4136     /* clear WS_VSCROLL */
4137     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4138 }
4139
4140 static void test_showwindow(void)
4141 {
4142     HWND hwnd, hchild;
4143     RECT rc;
4144
4145     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4146                            100, 100, 200, 200, 0, 0, 0, NULL);
4147     ok (hwnd != 0, "Failed to create overlapped window\n");
4148     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4149                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4150     ok (hchild != 0, "Failed to create child\n");
4151     flush_sequence();
4152
4153     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4154     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4155     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4156     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4157
4158     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4159     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4160     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4161     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4162     /* back to invisible */
4163     ShowWindow(hchild, SW_HIDE);
4164     ShowWindow(hwnd, SW_HIDE);
4165     flush_sequence();
4166     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4167     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4168     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4169     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4170     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4171     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4172     flush_sequence();
4173     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4174     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4175     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4176     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4177     ShowWindow( hwnd, SW_SHOW);
4178     flush_sequence();
4179     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4180     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4181     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4182
4183     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4184     ShowWindow( hchild, SW_HIDE);
4185     flush_sequence();
4186     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4187     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4188     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4189
4190     SetCapture(hchild);
4191     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4192     DestroyWindow(hchild);
4193     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4194
4195     DestroyWindow(hwnd);
4196     flush_sequence();
4197
4198     /* Popup windows */
4199     /* Test 1:
4200      * 1. Create invisible maximized popup window.
4201      * 2. Move and resize it.
4202      * 3. Show it maximized.
4203      */
4204     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4205     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4206                            100, 100, 200, 200, 0, 0, 0, NULL);
4207     ok (hwnd != 0, "Failed to create popup window\n");
4208     ok(IsZoomed(hwnd), "window should be maximized\n");
4209     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4210
4211     GetWindowRect(hwnd, &rc);
4212     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4213         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4214         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4215         rc.left, rc.top, rc.right, rc.bottom);
4216     /* Reset window's size & position */
4217     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4218     ok(IsZoomed(hwnd), "window should be maximized\n");
4219     flush_sequence();
4220
4221     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4222     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4223     ok(IsZoomed(hwnd), "window should be maximized\n");
4224     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4225
4226     GetWindowRect(hwnd, &rc);
4227     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4228         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4229         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4230         rc.left, rc.top, rc.right, rc.bottom);
4231     DestroyWindow(hwnd);
4232     flush_sequence();
4233
4234     /* Test 2:
4235      * 1. Create invisible maximized popup window.
4236      * 2. Show it maximized.
4237      */
4238     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4239     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4240                            100, 100, 200, 200, 0, 0, 0, NULL);
4241     ok (hwnd != 0, "Failed to create popup window\n");
4242     ok(IsZoomed(hwnd), "window should be maximized\n");
4243     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4244
4245     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4246     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4247     ok(IsZoomed(hwnd), "window should be maximized\n");
4248     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4249     DestroyWindow(hwnd);
4250     flush_sequence();
4251
4252     /* Test 3:
4253      * 1. Create visible maximized popup window.
4254      */
4255     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4256     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4257                            100, 100, 200, 200, 0, 0, 0, NULL);
4258     ok (hwnd != 0, "Failed to create popup window\n");
4259     ok(IsZoomed(hwnd), "window should be maximized\n");
4260     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4261     DestroyWindow(hwnd);
4262     flush_sequence();
4263
4264     /* Test 4:
4265      * 1. Create visible popup window.
4266      * 2. Maximize it.
4267      */
4268     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4269     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4270                            100, 100, 200, 200, 0, 0, 0, NULL);
4271     ok (hwnd != 0, "Failed to create popup window\n");
4272     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4273     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4274
4275     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4276     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4277     ok(IsZoomed(hwnd), "window should be maximized\n");
4278     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4279     DestroyWindow(hwnd);
4280     flush_sequence();
4281 }
4282
4283 static void test_sys_menu(void)
4284 {
4285     HWND hwnd;
4286     HMENU hmenu;
4287     UINT state;
4288
4289     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4290                            100, 100, 200, 200, 0, 0, 0, NULL);
4291     ok (hwnd != 0, "Failed to create overlapped window\n");
4292
4293     flush_sequence();
4294
4295     /* test existing window without CS_NOCLOSE style */
4296     hmenu = GetSystemMenu(hwnd, FALSE);
4297     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4298
4299     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4300     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4301     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4302
4303     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4304     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4305
4306     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4307     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4308     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4309
4310     EnableMenuItem(hmenu, SC_CLOSE, 0);
4311     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4312
4313     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4314     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4315     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4316
4317     /* test whether removing WS_SYSMENU destroys a system menu */
4318     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4319     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4320     flush_sequence();
4321     hmenu = GetSystemMenu(hwnd, FALSE);
4322     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4323
4324     DestroyWindow(hwnd);
4325
4326     /* test new window with CS_NOCLOSE style */
4327     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4328                            100, 100, 200, 200, 0, 0, 0, NULL);
4329     ok (hwnd != 0, "Failed to create overlapped window\n");
4330
4331     hmenu = GetSystemMenu(hwnd, FALSE);
4332     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4333
4334     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4335     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4336
4337     DestroyWindow(hwnd);
4338
4339     /* test new window without WS_SYSMENU style */
4340     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4341                            100, 100, 200, 200, 0, 0, 0, NULL);
4342     ok(hwnd != 0, "Failed to create overlapped window\n");
4343
4344     hmenu = GetSystemMenu(hwnd, FALSE);
4345     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4346
4347     DestroyWindow(hwnd);
4348 }
4349
4350 /* For shown WS_OVERLAPPEDWINDOW */
4351 static const struct message WmSetIcon_1[] = {
4352     { WM_SETICON, sent },
4353     { 0x00AE, sent|defwinproc|optional }, /* XP */
4354     { WM_GETTEXT, sent|defwinproc|optional },
4355     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4356     { 0 }
4357 };
4358
4359 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4360 static const struct message WmSetIcon_2[] = {
4361     { WM_SETICON, sent },
4362     { 0 }
4363 };
4364
4365 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4366 static const struct message WmInitEndSession[] = {
4367     { 0x003B, sent },
4368     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4369     { 0 }
4370 };
4371
4372 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4373 static const struct message WmInitEndSession_2[] = {
4374     { 0x003B, sent },
4375     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4376     { 0 }
4377 };
4378
4379 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4380 static const struct message WmInitEndSession_3[] = {
4381     { 0x003B, sent },
4382     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4383     { 0 }
4384 };
4385
4386 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4387 static const struct message WmInitEndSession_4[] = {
4388     { 0x003B, sent },
4389     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4390     { 0 }
4391 };
4392
4393 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4394 static const struct message WmInitEndSession_5[] = {
4395     { 0x003B, sent },
4396     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4397     { 0 }
4398 };
4399
4400 static const struct message WmOptionalPaint[] = {
4401     { WM_PAINT, sent|optional },
4402     { WM_NCPAINT, sent|beginpaint|optional },
4403     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4404     { WM_ERASEBKGND, sent|beginpaint|optional },
4405     { 0 }
4406 };
4407
4408 static const struct message WmZOrder[] = {
4409     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4410     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4411     { HCBT_ACTIVATE, hook },
4412     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4413     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4414     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4415     { WM_GETTEXT, sent|optional },
4416     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4417     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4418     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4419     { WM_GETTEXT, sent|defwinproc|optional },
4420     { WM_GETTEXT, sent|defwinproc|optional },
4421     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4422     { HCBT_SETFOCUS, hook },
4423     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4424     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4425     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4426     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4427     { WM_GETTEXT, sent|optional },
4428     { WM_NCCALCSIZE, sent|optional },
4429     { 0 }
4430 };
4431
4432 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4433 {
4434     DWORD ret;
4435     MSG msg;
4436
4437     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4438     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4439
4440     PostMessageA(hwnd, WM_USER, 0, 0);
4441
4442     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4443     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4444
4445     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4446     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4447
4448     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4449     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4450
4451     PostMessageA(hwnd, WM_USER, 0, 0);
4452
4453     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4454     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4455
4456     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4457     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4458
4459     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4460     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4461     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4462
4463     PostMessageA(hwnd, WM_USER, 0, 0);
4464
4465     /* new incoming message causes it to become signaled again */
4466     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4467     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4468
4469     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4470     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4471     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4472     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4473 }
4474
4475 /* test if we receive the right sequence of messages */
4476 static void test_messages(void)
4477 {
4478     HWND hwnd, hparent, hchild;
4479     HWND hchild2, hbutton;
4480     HMENU hmenu;
4481     MSG msg;
4482     LRESULT res;
4483
4484     flush_sequence();
4485
4486     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4487                            100, 100, 200, 200, 0, 0, 0, NULL);
4488     ok (hwnd != 0, "Failed to create overlapped window\n");
4489     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4490
4491     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4492     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4493     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4494
4495     /* test WM_SETREDRAW on a not visible top level window */
4496     test_WM_SETREDRAW(hwnd);
4497
4498     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4499     flush_events();
4500     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4501     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4502
4503     ok(GetActiveWindow() == hwnd, "window should be active\n");
4504     ok(GetFocus() == hwnd, "window should have input focus\n");
4505     ShowWindow(hwnd, SW_HIDE);
4506     flush_events();
4507     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4508
4509     ShowWindow(hwnd, SW_SHOW);
4510     flush_events();
4511     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4512
4513     ShowWindow(hwnd, SW_HIDE);
4514     flush_events();
4515     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4516
4517     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4518     flush_events();
4519     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4520     flush_sequence();
4521
4522     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4523     {
4524         ShowWindow(hwnd, SW_RESTORE);
4525         flush_events();
4526         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4527         flush_sequence();
4528     }
4529
4530     ShowWindow(hwnd, SW_MINIMIZE);
4531     flush_events();
4532     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4533     flush_sequence();
4534
4535     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4536     {
4537         ShowWindow(hwnd, SW_RESTORE);
4538         flush_events();
4539         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4540         flush_sequence();
4541     }
4542
4543     ShowWindow(hwnd, SW_SHOW);
4544     flush_events();
4545     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4546
4547     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4548     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4549     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4550     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4551
4552     /* test WM_SETREDRAW on a visible top level window */
4553     ShowWindow(hwnd, SW_SHOW);
4554     flush_events();
4555     test_WM_SETREDRAW(hwnd);
4556
4557     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4558     test_scroll_messages(hwnd);
4559
4560     /* test resizing and moving */
4561     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4562     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4563     flush_events();
4564     flush_sequence();
4565     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4566     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4567     flush_events();
4568     flush_sequence();
4569     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4570     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4571     flush_events();
4572     flush_sequence();
4573
4574     /* popups don't get WM_GETMINMAXINFO */
4575     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4576     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4577     flush_sequence();
4578     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4579     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4580
4581     DestroyWindow(hwnd);
4582     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4583
4584     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4585                               100, 100, 200, 200, 0, 0, 0, NULL);
4586     ok (hparent != 0, "Failed to create parent window\n");
4587     flush_sequence();
4588
4589     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4590                              0, 0, 10, 10, hparent, 0, 0, NULL);
4591     ok (hchild != 0, "Failed to create child window\n");
4592     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4593     DestroyWindow(hchild);
4594     flush_sequence();
4595
4596     /* visible child window with a caption */
4597     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4598                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4599                              0, 0, 10, 10, hparent, 0, 0, NULL);
4600     ok (hchild != 0, "Failed to create child window\n");
4601     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4602
4603     trace("testing scroll APIs on a visible child window %p\n", hchild);
4604     test_scroll_messages(hchild);
4605
4606     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4607     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4608
4609     DestroyWindow(hchild);
4610     flush_sequence();
4611
4612     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4613                              0, 0, 10, 10, hparent, 0, 0, NULL);
4614     ok (hchild != 0, "Failed to create child window\n");
4615     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4616     
4617     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4618                                100, 100, 50, 50, hparent, 0, 0, NULL);
4619     ok (hchild2 != 0, "Failed to create child2 window\n");
4620     flush_sequence();
4621
4622     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4623                               0, 100, 50, 50, hchild, 0, 0, NULL);
4624     ok (hbutton != 0, "Failed to create button window\n");
4625
4626     /* test WM_SETREDRAW on a not visible child window */
4627     test_WM_SETREDRAW(hchild);
4628
4629     ShowWindow(hchild, SW_SHOW);
4630     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4631
4632     /* check parent messages too */
4633     log_all_parent_messages++;
4634     ShowWindow(hchild, SW_HIDE);
4635     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4636     log_all_parent_messages--;
4637
4638     ShowWindow(hchild, SW_SHOW);
4639     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4640
4641     ShowWindow(hchild, SW_HIDE);
4642     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4643
4644     ShowWindow(hchild, SW_SHOW);
4645     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4646
4647     /* test WM_SETREDRAW on a visible child window */
4648     test_WM_SETREDRAW(hchild);
4649
4650     log_all_parent_messages++;
4651     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4652     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4653     log_all_parent_messages--;
4654
4655     ShowWindow(hchild, SW_HIDE);
4656     flush_sequence();
4657     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4658     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4659
4660     ShowWindow(hchild, SW_HIDE);
4661     flush_sequence();
4662     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4663     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4664
4665     /* DestroyWindow sequence below expects that a child has focus */
4666     SetFocus(hchild);
4667     flush_sequence();
4668
4669     DestroyWindow(hchild);
4670     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4671     DestroyWindow(hchild2);
4672     DestroyWindow(hbutton);
4673
4674     flush_sequence();
4675     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4676                              0, 0, 100, 100, hparent, 0, 0, NULL);
4677     ok (hchild != 0, "Failed to create child popup window\n");
4678     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4679     DestroyWindow(hchild);
4680
4681     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4682     flush_sequence();
4683     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4684                              0, 0, 100, 100, hparent, 0, 0, NULL);
4685     ok (hchild != 0, "Failed to create popup window\n");
4686     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4687     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4688     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4689     flush_sequence();
4690     ShowWindow(hchild, SW_SHOW);
4691     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4692     flush_sequence();
4693     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4694     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4695     flush_sequence();
4696     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4697     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4698     DestroyWindow(hchild);
4699
4700     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4701      * changes nothing in message sequences.
4702      */
4703     flush_sequence();
4704     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4705                              0, 0, 100, 100, hparent, 0, 0, NULL);
4706     ok (hchild != 0, "Failed to create popup window\n");
4707     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4708     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4709     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4710     flush_sequence();
4711     ShowWindow(hchild, SW_SHOW);
4712     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4713     flush_sequence();
4714     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4715     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4716     DestroyWindow(hchild);
4717
4718     flush_sequence();
4719     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4720                            0, 0, 100, 100, hparent, 0, 0, NULL);
4721     ok(hwnd != 0, "Failed to create custom dialog window\n");
4722     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4723
4724     if(0) {
4725     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4726     test_scroll_messages(hwnd);
4727     }
4728
4729     flush_sequence();
4730
4731     test_def_id = 1;
4732     SendMessage(hwnd, WM_NULL, 0, 0);
4733
4734     flush_sequence();
4735     after_end_dialog = 1;
4736     EndDialog( hwnd, 0 );
4737     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4738
4739     DestroyWindow(hwnd);
4740     after_end_dialog = 0;
4741     test_def_id = 0;
4742
4743     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4744                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4745     ok(hwnd != 0, "Failed to create custom dialog window\n");
4746     flush_sequence();
4747     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4748     ShowWindow(hwnd, SW_SHOW);
4749     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4750     DestroyWindow(hwnd);
4751
4752     flush_sequence();
4753     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4754     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4755
4756     DestroyWindow(hparent);
4757     flush_sequence();
4758
4759     /* Message sequence for SetMenu */
4760     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4761     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4762
4763     hmenu = CreateMenu();
4764     ok (hmenu != 0, "Failed to create menu\n");
4765     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4766     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4767                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4768     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4769     ok (SetMenu(hwnd, 0), "SetMenu\n");
4770     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4771     ok (SetMenu(hwnd, 0), "SetMenu\n");
4772     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4773     ShowWindow(hwnd, SW_SHOW);
4774     UpdateWindow( hwnd );
4775     flush_events();
4776     flush_sequence();
4777     ok (SetMenu(hwnd, 0), "SetMenu\n");
4778     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4779     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4780     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4781
4782     UpdateWindow( hwnd );
4783     flush_events();
4784     flush_sequence();
4785     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4786     flush_events();
4787     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4788
4789     DestroyWindow(hwnd);
4790     flush_sequence();
4791
4792     /* Message sequence for EnableWindow */
4793     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4794                               100, 100, 200, 200, 0, 0, 0, NULL);
4795     ok (hparent != 0, "Failed to create parent window\n");
4796     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4797                              0, 0, 10, 10, hparent, 0, 0, NULL);
4798     ok (hchild != 0, "Failed to create child window\n");
4799
4800     SetFocus(hchild);
4801     flush_events();
4802     flush_sequence();
4803
4804     EnableWindow(hparent, FALSE);
4805     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4806
4807     EnableWindow(hparent, TRUE);
4808     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4809
4810     flush_events();
4811     flush_sequence();
4812
4813     test_MsgWaitForMultipleObjects(hparent);
4814
4815     /* the following test causes an exception in user.exe under win9x */
4816     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4817     {
4818         DestroyWindow(hparent);
4819         flush_sequence();
4820         return;
4821     }
4822     PostMessageW( hparent, WM_USER+1, 0, 0 );
4823     /* PeekMessage(NULL) fails, but still removes the message */
4824     SetLastError(0xdeadbeef);
4825     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4826     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4827         GetLastError() == 0xdeadbeef, /* NT4 */
4828         "last error is %d\n", GetLastError() );
4829     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4830     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4831
4832     DestroyWindow(hchild);
4833     DestroyWindow(hparent);
4834     flush_sequence();
4835
4836     /* Message sequences for WM_SETICON */
4837     trace("testing WM_SETICON\n");
4838     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4839                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4840                            NULL, NULL, 0);
4841     ShowWindow(hwnd, SW_SHOW);
4842     UpdateWindow(hwnd);
4843     flush_events();
4844     flush_sequence();
4845     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4846     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4847
4848     ShowWindow(hwnd, SW_HIDE);
4849     flush_events();
4850     flush_sequence();
4851     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4852     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4853     DestroyWindow(hwnd);
4854     flush_sequence();
4855
4856     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4857                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4858                            NULL, NULL, 0);
4859     ShowWindow(hwnd, SW_SHOW);
4860     UpdateWindow(hwnd);
4861     flush_events();
4862     flush_sequence();
4863     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4864     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4865
4866     ShowWindow(hwnd, SW_HIDE);
4867     flush_events();
4868     flush_sequence();
4869     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4870     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4871
4872     flush_sequence();
4873     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4874     if (!res)
4875     {
4876         todo_wine win_skip( "Message 0x3b not supported\n" );
4877         goto done;
4878     }
4879     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4880     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4881     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4882     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4883     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4884     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4885     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4886     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4887
4888     flush_sequence();
4889     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4890     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4891     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4892     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4893     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4894     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4895
4896     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4897     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4898     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4899
4900     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4901     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4902     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4903
4904 done:
4905     DestroyWindow(hwnd);
4906     flush_sequence();
4907 }
4908
4909 static void test_setwindowpos(void)
4910 {
4911     HWND hwnd;
4912     RECT rc;
4913     LRESULT res;
4914     const INT winX = 100;
4915     const INT winY = 100;
4916     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4917
4918     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4919                            0, 0, winX, winY, 0,
4920                            NULL, NULL, 0);
4921
4922     GetWindowRect(hwnd, &rc);
4923     expect(sysX, rc.right);
4924     expect(winY, rc.bottom);
4925
4926     flush_events();
4927     flush_sequence();
4928     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4929     ok_sequence(WmZOrder, "Z-Order", TRUE);
4930     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4931
4932     GetWindowRect(hwnd, &rc);
4933     expect(sysX, rc.right);
4934     expect(winY, rc.bottom);
4935     DestroyWindow(hwnd);
4936 }
4937
4938 static void invisible_parent_tests(void)
4939 {
4940     HWND hparent, hchild;
4941
4942     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4943                               100, 100, 200, 200, 0, 0, 0, NULL);
4944     ok (hparent != 0, "Failed to create parent window\n");
4945     flush_sequence();
4946
4947     /* test showing child with hidden parent */
4948
4949     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4950                              0, 0, 10, 10, hparent, 0, 0, NULL);
4951     ok (hchild != 0, "Failed to create child window\n");
4952     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4953
4954     ShowWindow( hchild, SW_MINIMIZE );
4955     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4956     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4957     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4958
4959     /* repeat */
4960     flush_events();
4961     flush_sequence();
4962     ShowWindow( hchild, SW_MINIMIZE );
4963     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4964
4965     DestroyWindow(hchild);
4966     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4967                              0, 0, 10, 10, hparent, 0, 0, NULL);
4968     flush_sequence();
4969
4970     ShowWindow( hchild, SW_MAXIMIZE );
4971     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4972     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4973     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4974
4975     /* repeat */
4976     flush_events();
4977     flush_sequence();
4978     ShowWindow( hchild, SW_MAXIMIZE );
4979     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4980
4981     DestroyWindow(hchild);
4982     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4983                              0, 0, 10, 10, hparent, 0, 0, NULL);
4984     flush_sequence();
4985
4986     ShowWindow( hchild, SW_RESTORE );
4987     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4988     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4989     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4990
4991     DestroyWindow(hchild);
4992     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4993                              0, 0, 10, 10, hparent, 0, 0, NULL);
4994     flush_sequence();
4995
4996     ShowWindow( hchild, SW_SHOWMINIMIZED );
4997     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4998     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4999     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5000
5001     /* repeat */
5002     flush_events();
5003     flush_sequence();
5004     ShowWindow( hchild, SW_SHOWMINIMIZED );
5005     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5006
5007     DestroyWindow(hchild);
5008     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5009                              0, 0, 10, 10, hparent, 0, 0, NULL);
5010     flush_sequence();
5011
5012     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5013     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5014     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5015     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5016     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5017
5018     DestroyWindow(hchild);
5019     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5020                              0, 0, 10, 10, hparent, 0, 0, NULL);
5021     flush_sequence();
5022
5023     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5024     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5025     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5026     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5027
5028     /* repeat */
5029     flush_events();
5030     flush_sequence();
5031     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5032     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5033
5034     DestroyWindow(hchild);
5035     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5036                              0, 0, 10, 10, hparent, 0, 0, NULL);
5037     flush_sequence();
5038
5039     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5040     ShowWindow( hchild, SW_FORCEMINIMIZE );
5041     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5042 todo_wine {
5043     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5044 }
5045     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5046
5047     DestroyWindow(hchild);
5048     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5049                              0, 0, 10, 10, hparent, 0, 0, NULL);
5050     flush_sequence();
5051
5052     ShowWindow( hchild, SW_SHOWNA );
5053     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5054     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5055     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5056
5057     /* repeat */
5058     flush_events();
5059     flush_sequence();
5060     ShowWindow( hchild, SW_SHOWNA );
5061     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5062
5063     DestroyWindow(hchild);
5064     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5065                              0, 0, 10, 10, hparent, 0, 0, NULL);
5066     flush_sequence();
5067
5068     ShowWindow( hchild, SW_SHOW );
5069     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5070     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5071     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5072
5073     /* repeat */
5074     flush_events();
5075     flush_sequence();
5076     ShowWindow( hchild, SW_SHOW );
5077     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5078
5079     ShowWindow( hchild, SW_HIDE );
5080     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5081     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5082     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5083
5084     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5085     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5086     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5087     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5088
5089     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5090     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5091     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5092     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5093
5094     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5095     flush_sequence();
5096     DestroyWindow(hchild);
5097     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5098
5099     DestroyWindow(hparent);
5100     flush_sequence();
5101 }
5102
5103 /****************** button message test *************************/
5104 #define ID_BUTTON 0x000e
5105
5106 static const struct message WmSetFocusButtonSeq[] =
5107 {
5108     { HCBT_SETFOCUS, hook },
5109     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5110     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5111     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5112     { WM_SETFOCUS, sent|wparam, 0 },
5113     { WM_CTLCOLORBTN, sent|parent },
5114     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5115     { WM_APP, sent|wparam|lparam, 0, 0 },
5116     { 0 }
5117 };
5118 static const struct message WmKillFocusButtonSeq[] =
5119 {
5120     { HCBT_SETFOCUS, hook },
5121     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5122     { WM_KILLFOCUS, sent|wparam, 0 },
5123     { WM_CTLCOLORBTN, sent|parent },
5124     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5125     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5126     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5127     { WM_APP, sent|wparam|lparam, 0, 0 },
5128     { WM_PAINT, sent },
5129     { WM_CTLCOLORBTN, sent|parent },
5130     { 0 }
5131 };
5132 static const struct message WmSetFocusStaticSeq[] =
5133 {
5134     { HCBT_SETFOCUS, hook },
5135     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5136     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5137     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5138     { WM_SETFOCUS, sent|wparam, 0 },
5139     { WM_CTLCOLORSTATIC, sent|parent },
5140     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5141     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5142     { WM_APP, sent|wparam|lparam, 0, 0 },
5143     { 0 }
5144 };
5145 static const struct message WmKillFocusStaticSeq[] =
5146 {
5147     { HCBT_SETFOCUS, hook },
5148     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5149     { WM_KILLFOCUS, sent|wparam, 0 },
5150     { WM_CTLCOLORSTATIC, sent|parent },
5151     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5152     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5153     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5154     { WM_APP, sent|wparam|lparam, 0, 0 },
5155     { WM_PAINT, sent },
5156     { WM_CTLCOLORSTATIC, sent|parent },
5157     { 0 }
5158 };
5159 static const struct message WmSetFocusOwnerdrawSeq[] =
5160 {
5161     { HCBT_SETFOCUS, hook },
5162     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5163     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5164     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5165     { WM_SETFOCUS, sent|wparam, 0 },
5166     { WM_CTLCOLORBTN, sent|parent },
5167     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5168     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5169     { WM_APP, sent|wparam|lparam, 0, 0 },
5170     { 0 }
5171 };
5172 static const struct message WmKillFocusOwnerdrawSeq[] =
5173 {
5174     { HCBT_SETFOCUS, hook },
5175     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5176     { WM_KILLFOCUS, sent|wparam, 0 },
5177     { WM_CTLCOLORBTN, sent|parent },
5178     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5179     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5180     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5181     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5182     { WM_APP, sent|wparam|lparam, 0, 0 },
5183     { WM_PAINT, sent },
5184     { WM_CTLCOLORBTN, sent|parent },
5185     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5186     { 0 }
5187 };
5188 static const struct message WmLButtonDownSeq[] =
5189 {
5190     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5191     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5192     { HCBT_SETFOCUS, hook },
5193     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5194     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5195     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5196     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5197     { WM_CTLCOLORBTN, sent|defwinproc },
5198     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5199     { WM_CTLCOLORBTN, sent|defwinproc },
5200     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5201     { 0 }
5202 };
5203 static const struct message WmLButtonUpSeq[] =
5204 {
5205     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5206     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5207     { WM_CTLCOLORBTN, sent|defwinproc },
5208     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5209     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5210     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5211     { 0 }
5212 };
5213 static const struct message WmSetFontButtonSeq[] =
5214 {
5215     { WM_SETFONT, sent },
5216     { WM_PAINT, sent },
5217     { WM_ERASEBKGND, sent|defwinproc|optional },
5218     { WM_CTLCOLORBTN, sent|defwinproc },
5219     { 0 }
5220 };
5221 static const struct message WmSetStyleButtonSeq[] =
5222 {
5223     { BM_SETSTYLE, sent },
5224     { WM_APP, sent|wparam|lparam, 0, 0 },
5225     { WM_PAINT, sent },
5226     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5227     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5228     { WM_CTLCOLORBTN, sent|parent },
5229     { 0 }
5230 };
5231 static const struct message WmSetStyleStaticSeq[] =
5232 {
5233     { BM_SETSTYLE, sent },
5234     { WM_APP, sent|wparam|lparam, 0, 0 },
5235     { WM_PAINT, sent },
5236     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5237     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5238     { WM_CTLCOLORSTATIC, sent|parent },
5239     { 0 }
5240 };
5241 static const struct message WmSetStyleUserSeq[] =
5242 {
5243     { BM_SETSTYLE, sent },
5244     { WM_APP, sent|wparam|lparam, 0, 0 },
5245     { WM_PAINT, sent },
5246     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5247     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5248     { WM_CTLCOLORBTN, sent|parent },
5249     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5250     { 0 }
5251 };
5252 static const struct message WmSetStyleOwnerdrawSeq[] =
5253 {
5254     { BM_SETSTYLE, sent },
5255     { WM_APP, sent|wparam|lparam, 0, 0 },
5256     { WM_PAINT, sent },
5257     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5258     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5259     { WM_CTLCOLORBTN, sent|parent },
5260     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5261     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5262     { 0 }
5263 };
5264 static const struct message WmSetStateButtonSeq[] =
5265 {
5266     { BM_SETSTATE, sent },
5267     { WM_CTLCOLORBTN, sent|parent },
5268     { WM_APP, sent|wparam|lparam, 0, 0 },
5269     { 0 }
5270 };
5271 static const struct message WmSetStateStaticSeq[] =
5272 {
5273     { BM_SETSTATE, sent },
5274     { WM_CTLCOLORSTATIC, sent|parent },
5275     { WM_APP, sent|wparam|lparam, 0, 0 },
5276     { 0 }
5277 };
5278 static const struct message WmSetStateUserSeq[] =
5279 {
5280     { BM_SETSTATE, sent },
5281     { WM_CTLCOLORBTN, sent|parent },
5282     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5283     { WM_APP, sent|wparam|lparam, 0, 0 },
5284     { 0 }
5285 };
5286 static const struct message WmSetStateOwnerdrawSeq[] =
5287 {
5288     { BM_SETSTATE, sent },
5289     { WM_CTLCOLORBTN, sent|parent },
5290     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5291     { WM_APP, sent|wparam|lparam, 0, 0 },
5292     { 0 }
5293 };
5294 static const struct message WmClearStateButtonSeq[] =
5295 {
5296     { BM_SETSTATE, sent },
5297     { WM_CTLCOLORBTN, sent|parent },
5298     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5299     { WM_APP, sent|wparam|lparam, 0, 0 },
5300     { 0 }
5301 };
5302 static const struct message WmClearStateOwnerdrawSeq[] =
5303 {
5304     { BM_SETSTATE, sent },
5305     { WM_CTLCOLORBTN, sent|parent },
5306     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5307     { WM_APP, sent|wparam|lparam, 0, 0 },
5308     { 0 }
5309 };
5310 static const struct message WmSetCheckIgnoredSeq[] =
5311 {
5312     { BM_SETCHECK, sent },
5313     { WM_APP, sent|wparam|lparam, 0, 0 },
5314     { 0 }
5315 };
5316 static const struct message WmSetCheckStaticSeq[] =
5317 {
5318     { BM_SETCHECK, sent },
5319     { WM_CTLCOLORSTATIC, sent|parent },
5320     { WM_APP, sent|wparam|lparam, 0, 0 },
5321     { 0 }
5322 };
5323
5324 static WNDPROC old_button_proc;
5325
5326 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5327 {
5328     static LONG defwndproc_counter = 0;
5329     LRESULT ret;
5330     struct recvd_message msg;
5331
5332     if (ignore_message( message )) return 0;
5333
5334     switch (message)
5335     {
5336     case WM_SYNCPAINT:
5337         break;
5338     case BM_SETSTATE:
5339         if (GetCapture())
5340             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5341         /* fall through */
5342     default:
5343         msg.hwnd = hwnd;
5344         msg.message = message;
5345         msg.flags = sent|wparam|lparam;
5346         if (defwndproc_counter) msg.flags |= defwinproc;
5347         msg.wParam = wParam;
5348         msg.lParam = lParam;
5349         msg.descr = "button";
5350         add_message(&msg);
5351     }
5352
5353     defwndproc_counter++;
5354     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5355     defwndproc_counter--;
5356
5357     return ret;
5358 }
5359
5360 static void subclass_button(void)
5361 {
5362     WNDCLASSA cls;
5363
5364     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5365
5366     old_button_proc = cls.lpfnWndProc;
5367
5368     cls.hInstance = GetModuleHandle(0);
5369     cls.lpfnWndProc = button_hook_proc;
5370     cls.lpszClassName = "my_button_class";
5371     UnregisterClass(cls.lpszClassName, cls.hInstance);
5372     if (!RegisterClassA(&cls)) assert(0);
5373 }
5374
5375 static void test_button_messages(void)
5376 {
5377     static const struct
5378     {
5379         DWORD style;
5380         DWORD dlg_code;
5381         const struct message *setfocus;
5382         const struct message *killfocus;
5383         const struct message *setstyle;
5384         const struct message *setstate;
5385         const struct message *clearstate;
5386         const struct message *setcheck;
5387     } button[] = {
5388         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5389           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5390           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5391         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5392           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5393           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5394         { BS_CHECKBOX, DLGC_BUTTON,
5395           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5396           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5397         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5398           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5399           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5400         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5401           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5402           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5403         { BS_3STATE, DLGC_BUTTON,
5404           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5405           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5406         { BS_AUTO3STATE, DLGC_BUTTON,
5407           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5408           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5409         { BS_GROUPBOX, DLGC_STATIC,
5410           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5411           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5412         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5413           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5414           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5415         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5416           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5417           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5418         { BS_OWNERDRAW, DLGC_BUTTON,
5419           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5420           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5421     };
5422     unsigned int i;
5423     HWND hwnd, parent;
5424     DWORD dlg_code;
5425     HFONT zfont;
5426
5427     /* selection with VK_SPACE should capture button window */
5428     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5429                            0, 0, 50, 14, 0, 0, 0, NULL);
5430     ok(hwnd != 0, "Failed to create button window\n");
5431     ReleaseCapture();
5432     SetFocus(hwnd);
5433     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5434     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5435     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5436     DestroyWindow(hwnd);
5437
5438     subclass_button();
5439
5440     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5441                              100, 100, 200, 200, 0, 0, 0, NULL);
5442     ok(parent != 0, "Failed to create parent window\n");
5443
5444     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5445     {
5446         MSG msg;
5447         DWORD style, state;
5448
5449         trace("button style %08x\n", button[i].style);
5450
5451         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5452                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5453         ok(hwnd != 0, "Failed to create button window\n");
5454
5455         style = GetWindowLongA(hwnd, GWL_STYLE);
5456         style &= ~(WS_CHILD | BS_NOTIFY);
5457         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5458         if (button[i].style == BS_USERBUTTON)
5459             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5460         else
5461             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5462
5463         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5464         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5465
5466         ShowWindow(hwnd, SW_SHOW);
5467         UpdateWindow(hwnd);
5468         SetFocus(0);
5469         flush_events();
5470         SetFocus(0);
5471         flush_sequence();
5472
5473         log_all_parent_messages++;
5474
5475         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5476         SetFocus(hwnd);
5477         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5478         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5479         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5480
5481         SetFocus(0);
5482         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5483         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5484         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5485
5486         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5487
5488         SendMessage(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5489         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5490         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5491         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5492
5493         style = GetWindowLongA(hwnd, GWL_STYLE);
5494         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5495         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5496         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5497
5498         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5499         ok(state == 0, "expected state 0, got %04x\n", state);
5500
5501         flush_sequence();
5502
5503         SendMessage(hwnd, BM_SETSTATE, TRUE, 0);
5504         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5505         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5506         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5507
5508         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5509         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5510
5511         style = GetWindowLongA(hwnd, GWL_STYLE);
5512         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5513         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5514
5515         flush_sequence();
5516
5517         SendMessage(hwnd, BM_SETSTATE, FALSE, 0);
5518         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5519         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5520         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5521
5522         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5523         ok(state == 0, "expected state 0, got %04x\n", state);
5524
5525         style = GetWindowLongA(hwnd, GWL_STYLE);
5526         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5527         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5528
5529         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5530         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5531
5532         flush_sequence();
5533
5534         SendMessage(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5535         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5536         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5537         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5538
5539         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5540         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5541
5542         style = GetWindowLongA(hwnd, GWL_STYLE);
5543         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5544         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5545
5546         flush_sequence();
5547
5548         SendMessage(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5549         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5550         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5551         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5552
5553         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5554         if (button[i].style == BS_PUSHBUTTON ||
5555             button[i].style == BS_DEFPUSHBUTTON ||
5556             button[i].style == BS_GROUPBOX ||
5557             button[i].style == BS_USERBUTTON ||
5558             button[i].style == BS_OWNERDRAW)
5559             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5560         else
5561             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5562
5563         style = GetWindowLongA(hwnd, GWL_STYLE);
5564         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5565         if (button[i].style == BS_RADIOBUTTON ||
5566             button[i].style == BS_AUTORADIOBUTTON)
5567             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5568         else
5569             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5570
5571         log_all_parent_messages--;
5572
5573         DestroyWindow(hwnd);
5574     }
5575
5576     DestroyWindow(parent);
5577
5578     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5579                            0, 0, 50, 14, 0, 0, 0, NULL);
5580     ok(hwnd != 0, "Failed to create button window\n");
5581
5582     SetForegroundWindow(hwnd);
5583     flush_events();
5584
5585     SetActiveWindow(hwnd);
5586     SetFocus(0);
5587     flush_sequence();
5588
5589     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5590     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5591
5592     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5593     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5594
5595     flush_sequence();
5596     zfont = GetStockObject(SYSTEM_FONT);
5597     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5598     UpdateWindow(hwnd);
5599     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5600
5601     DestroyWindow(hwnd);
5602 }
5603
5604 /****************** static message test *************************/
5605 static const struct message WmSetFontStaticSeq[] =
5606 {
5607     { WM_SETFONT, sent },
5608     { WM_PAINT, sent|defwinproc|optional },
5609     { WM_ERASEBKGND, sent|defwinproc|optional },
5610     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5611     { 0 }
5612 };
5613
5614 static WNDPROC old_static_proc;
5615
5616 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5617 {
5618     static LONG defwndproc_counter = 0;
5619     LRESULT ret;
5620     struct recvd_message msg;
5621
5622     if (ignore_message( message )) return 0;
5623
5624     msg.hwnd = hwnd;
5625     msg.message = message;
5626     msg.flags = sent|wparam|lparam;
5627     if (defwndproc_counter) msg.flags |= defwinproc;
5628     msg.wParam = wParam;
5629     msg.lParam = lParam;
5630     msg.descr = "static";
5631     add_message(&msg);
5632
5633     defwndproc_counter++;
5634     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5635     defwndproc_counter--;
5636
5637     return ret;
5638 }
5639
5640 static void subclass_static(void)
5641 {
5642     WNDCLASSA cls;
5643
5644     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5645
5646     old_static_proc = cls.lpfnWndProc;
5647
5648     cls.hInstance = GetModuleHandle(0);
5649     cls.lpfnWndProc = static_hook_proc;
5650     cls.lpszClassName = "my_static_class";
5651     UnregisterClass(cls.lpszClassName, cls.hInstance);
5652     if (!RegisterClassA(&cls)) assert(0);
5653 }
5654
5655 static void test_static_messages(void)
5656 {
5657     /* FIXME: make as comprehensive as the button message test */
5658     static const struct
5659     {
5660         DWORD style;
5661         DWORD dlg_code;
5662         const struct message *setfont;
5663     } static_ctrl[] = {
5664         { SS_LEFT, DLGC_STATIC,
5665           WmSetFontStaticSeq }
5666     };
5667     unsigned int i;
5668     HWND hwnd;
5669     DWORD dlg_code;
5670
5671     subclass_static();
5672
5673     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5674     {
5675         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5676                                0, 0, 50, 14, 0, 0, 0, NULL);
5677         ok(hwnd != 0, "Failed to create static window\n");
5678
5679         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5680         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5681
5682         ShowWindow(hwnd, SW_SHOW);
5683         UpdateWindow(hwnd);
5684         SetFocus(0);
5685         flush_sequence();
5686
5687         trace("static style %08x\n", static_ctrl[i].style);
5688         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5689         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5690
5691         DestroyWindow(hwnd);
5692     }
5693 }
5694
5695 /****************** ComboBox message test *************************/
5696 #define ID_COMBOBOX 0x000f
5697
5698 static const struct message WmKeyDownComboSeq[] =
5699 {
5700     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5701     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5702     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5703     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5704     { WM_CTLCOLOREDIT, sent|parent },
5705     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5706     { 0 }
5707 };
5708
5709 static WNDPROC old_combobox_proc;
5710
5711 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5712 {
5713     static LONG defwndproc_counter = 0;
5714     LRESULT ret;
5715     struct recvd_message msg;
5716
5717     /* do not log painting messages */
5718     if (message != WM_PAINT &&
5719         message != WM_NCPAINT &&
5720         message != WM_SYNCPAINT &&
5721         message != WM_ERASEBKGND &&
5722         message != WM_NCHITTEST &&
5723         message != WM_GETTEXT &&
5724         !ignore_message( message ))
5725     {
5726         msg.hwnd = hwnd;
5727         msg.message = message;
5728         msg.flags = sent|wparam|lparam;
5729         if (defwndproc_counter) msg.flags |= defwinproc;
5730         msg.wParam = wParam;
5731         msg.lParam = lParam;
5732         msg.descr = "combo";
5733         add_message(&msg);
5734     }
5735
5736     defwndproc_counter++;
5737     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5738     defwndproc_counter--;
5739
5740     return ret;
5741 }
5742
5743 static void subclass_combobox(void)
5744 {
5745     WNDCLASSA cls;
5746
5747     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5748
5749     old_combobox_proc = cls.lpfnWndProc;
5750
5751     cls.hInstance = GetModuleHandle(0);
5752     cls.lpfnWndProc = combobox_hook_proc;
5753     cls.lpszClassName = "my_combobox_class";
5754     UnregisterClass(cls.lpszClassName, cls.hInstance);
5755     if (!RegisterClassA(&cls)) assert(0);
5756 }
5757
5758 static void test_combobox_messages(void)
5759 {
5760     HWND parent, combo;
5761     LRESULT ret;
5762
5763     subclass_combobox();
5764
5765     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5766                              100, 100, 200, 200, 0, 0, 0, NULL);
5767     ok(parent != 0, "Failed to create parent window\n");
5768     flush_sequence();
5769
5770     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5771                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5772     ok(combo != 0, "Failed to create combobox window\n");
5773
5774     UpdateWindow(combo);
5775
5776     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5777     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5778
5779     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5780     ok(ret == 0, "expected 0, got %ld\n", ret);
5781     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5782     ok(ret == 1, "expected 1, got %ld\n", ret);
5783     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5784     ok(ret == 2, "expected 2, got %ld\n", ret);
5785
5786     SendMessage(combo, CB_SETCURSEL, 0, 0);
5787     SetFocus(combo);
5788     flush_sequence();
5789
5790     log_all_parent_messages++;
5791     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5792     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5793     log_all_parent_messages--;
5794     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5795
5796     DestroyWindow(combo);
5797     DestroyWindow(parent);
5798 }
5799
5800 /****************** WM_IME_KEYDOWN message test *******************/
5801
5802 static const struct message WmImeKeydownMsgSeq_0[] =
5803 {
5804     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5805     { WM_CHAR, wparam, 'A' },
5806     { 0 }
5807 };
5808
5809 static const struct message WmImeKeydownMsgSeq_1[] =
5810 {
5811     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5812     { WM_CHAR,    optional|wparam, VK_RETURN },
5813     { 0 }
5814 };
5815
5816 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5817 {
5818     struct recvd_message msg;
5819
5820     msg.hwnd = hwnd;
5821     msg.message = message;
5822     msg.flags = wparam|lparam;
5823     msg.wParam = wParam;
5824     msg.lParam = lParam;
5825     msg.descr = "wmime_keydown";
5826     add_message(&msg);
5827
5828     return DefWindowProcA(hwnd, message, wParam, lParam);
5829 }
5830
5831 static void register_wmime_keydown_class(void)
5832 {
5833     WNDCLASSA cls;
5834
5835     ZeroMemory(&cls, sizeof(WNDCLASSA));
5836     cls.lpfnWndProc = wmime_keydown_procA;
5837     cls.hInstance = GetModuleHandleA(0);
5838     cls.lpszClassName = "wmime_keydown_class";
5839     if (!RegisterClassA(&cls)) assert(0);
5840 }
5841
5842 static void test_wmime_keydown_message(void)
5843 {
5844     HWND hwnd;
5845     MSG msg;
5846
5847     trace("Message sequences by WM_IME_KEYDOWN\n");
5848
5849     register_wmime_keydown_class();
5850     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5851                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5852                            NULL, NULL, 0);
5853     flush_events();
5854     flush_sequence();
5855
5856     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5857     SendMessage(hwnd, WM_CHAR, 'A', 1);
5858     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5859
5860     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5861     {
5862         TranslateMessage(&msg);
5863         DispatchMessage(&msg);
5864     }
5865     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5866
5867     DestroyWindow(hwnd);
5868 }
5869
5870 /************* painting message test ********************/
5871
5872 void dump_region(HRGN hrgn)
5873 {
5874     DWORD i, size;
5875     RGNDATA *data = NULL;
5876     RECT *rect;
5877
5878     if (!hrgn)
5879     {
5880         printf( "null region\n" );
5881         return;
5882     }
5883     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5884     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5885     GetRegionData( hrgn, size, data );
5886     printf("%d rects:", data->rdh.nCount );
5887     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5888         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5889     printf("\n");
5890     HeapFree( GetProcessHeap(), 0, data );
5891 }
5892
5893 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5894 {
5895     INT ret;
5896     RECT r1, r2;
5897     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5898     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5899
5900     ret = GetUpdateRgn( hwnd, update, FALSE );
5901     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5902     if (ret == NULLREGION)
5903     {
5904         ok( !hrgn, "Update region shouldn't be empty\n" );
5905     }
5906     else
5907     {
5908         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5909         {
5910             ok( 0, "Regions are different\n" );
5911             if (winetest_debug > 0)
5912             {
5913                 printf( "Update region: " );
5914                 dump_region( update );
5915                 printf( "Wanted region: " );
5916                 dump_region( hrgn );
5917             }
5918         }
5919     }
5920     GetRgnBox( update, &r1 );
5921     GetUpdateRect( hwnd, &r2, FALSE );
5922     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5923         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5924         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5925
5926     DeleteObject( tmp );
5927     DeleteObject( update );
5928 }
5929
5930 static const struct message WmInvalidateRgn[] = {
5931     { WM_NCPAINT, sent },
5932     { WM_GETTEXT, sent|defwinproc|optional },
5933     { 0 }
5934 };
5935
5936 static const struct message WmGetUpdateRect[] = {
5937     { WM_NCPAINT, sent },
5938     { WM_GETTEXT, sent|defwinproc|optional },
5939     { WM_PAINT, sent },
5940     { 0 }
5941 };
5942
5943 static const struct message WmInvalidateFull[] = {
5944     { WM_NCPAINT, sent|wparam, 1 },
5945     { WM_GETTEXT, sent|defwinproc|optional },
5946     { 0 }
5947 };
5948
5949 static const struct message WmInvalidateErase[] = {
5950     { WM_NCPAINT, sent|wparam, 1 },
5951     { WM_GETTEXT, sent|defwinproc|optional },
5952     { WM_ERASEBKGND, sent },
5953     { 0 }
5954 };
5955
5956 static const struct message WmInvalidatePaint[] = {
5957     { WM_PAINT, sent },
5958     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5959     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5960     { 0 }
5961 };
5962
5963 static const struct message WmInvalidateErasePaint[] = {
5964     { WM_PAINT, sent },
5965     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5966     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5967     { WM_ERASEBKGND, sent|beginpaint|optional },
5968     { 0 }
5969 };
5970
5971 static const struct message WmInvalidateErasePaint2[] = {
5972     { WM_PAINT, sent },
5973     { WM_NCPAINT, sent|beginpaint },
5974     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5975     { WM_ERASEBKGND, sent|beginpaint|optional },
5976     { 0 }
5977 };
5978
5979 static const struct message WmErase[] = {
5980     { WM_ERASEBKGND, sent },
5981     { 0 }
5982 };
5983
5984 static const struct message WmPaint[] = {
5985     { WM_PAINT, sent },
5986     { 0 }
5987 };
5988
5989 static const struct message WmParentOnlyPaint[] = {
5990     { WM_PAINT, sent|parent },
5991     { 0 }
5992 };
5993
5994 static const struct message WmInvalidateParent[] = {
5995     { WM_NCPAINT, sent|parent },
5996     { WM_GETTEXT, sent|defwinproc|parent|optional },
5997     { WM_ERASEBKGND, sent|parent },
5998     { 0 }
5999 };
6000
6001 static const struct message WmInvalidateParentChild[] = {
6002     { WM_NCPAINT, sent|parent },
6003     { WM_GETTEXT, sent|defwinproc|parent|optional },
6004     { WM_ERASEBKGND, sent|parent },
6005     { WM_NCPAINT, sent },
6006     { WM_GETTEXT, sent|defwinproc|optional },
6007     { WM_ERASEBKGND, sent },
6008     { 0 }
6009 };
6010
6011 static const struct message WmInvalidateParentChild2[] = {
6012     { WM_ERASEBKGND, sent|parent },
6013     { WM_NCPAINT, sent },
6014     { WM_GETTEXT, sent|defwinproc|optional },
6015     { WM_ERASEBKGND, sent },
6016     { 0 }
6017 };
6018
6019 static const struct message WmParentPaint[] = {
6020     { WM_PAINT, sent|parent },
6021     { WM_PAINT, sent },
6022     { 0 }
6023 };
6024
6025 static const struct message WmParentPaintNc[] = {
6026     { WM_PAINT, sent|parent },
6027     { WM_PAINT, sent },
6028     { WM_NCPAINT, sent|beginpaint },
6029     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6030     { WM_ERASEBKGND, sent|beginpaint|optional },
6031     { 0 }
6032 };
6033
6034 static const struct message WmChildPaintNc[] = {
6035     { WM_PAINT, sent },
6036     { WM_NCPAINT, sent|beginpaint },
6037     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6038     { WM_ERASEBKGND, sent|beginpaint|optional },
6039     { 0 }
6040 };
6041
6042 static const struct message WmParentErasePaint[] = {
6043     { WM_PAINT, sent|parent },
6044     { WM_NCPAINT, sent|parent|beginpaint },
6045     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6046     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6047     { WM_PAINT, sent },
6048     { WM_NCPAINT, sent|beginpaint },
6049     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6050     { WM_ERASEBKGND, sent|beginpaint|optional },
6051     { 0 }
6052 };
6053
6054 static const struct message WmParentOnlyNcPaint[] = {
6055     { WM_PAINT, sent|parent },
6056     { WM_NCPAINT, sent|parent|beginpaint },
6057     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6058     { 0 }
6059 };
6060
6061 static const struct message WmSetParentStyle[] = {
6062     { WM_STYLECHANGING, sent|parent },
6063     { WM_STYLECHANGED, sent|parent },
6064     { 0 }
6065 };
6066
6067 static void test_paint_messages(void)
6068 {
6069     BOOL ret;
6070     RECT rect;
6071     POINT pt;
6072     MSG msg;
6073     HWND hparent, hchild;
6074     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6075     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6076     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6077                                 100, 100, 200, 200, 0, 0, 0, NULL);
6078     ok (hwnd != 0, "Failed to create overlapped window\n");
6079
6080     ShowWindow( hwnd, SW_SHOW );
6081     UpdateWindow( hwnd );
6082     flush_events();
6083     flush_sequence();
6084
6085     check_update_rgn( hwnd, 0 );
6086     SetRectRgn( hrgn, 10, 10, 20, 20 );
6087     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6088     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6089     check_update_rgn( hwnd, hrgn );
6090     SetRectRgn( hrgn2, 20, 20, 30, 30 );
6091     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6092     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6093     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6094     check_update_rgn( hwnd, hrgn );
6095     /* validate everything */
6096     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6097     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6098     check_update_rgn( hwnd, 0 );
6099
6100     /* test empty region */
6101     SetRectRgn( hrgn, 10, 10, 10, 15 );
6102     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6103     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6104     check_update_rgn( hwnd, 0 );
6105     /* test empty rect */
6106     SetRect( &rect, 10, 10, 10, 15 );
6107     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6108     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6109     check_update_rgn( hwnd, 0 );
6110
6111     /* flush pending messages */
6112     flush_events();
6113     flush_sequence();
6114
6115     GetClientRect( hwnd, &rect );
6116     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6117     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6118      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6119      */
6120     trace("testing InvalidateRect(0, NULL, FALSE)\n");
6121     SetRectEmpty( &rect );
6122     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6123     check_update_rgn( hwnd, hrgn );
6124     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6125     flush_events();
6126     ok_sequence( WmPaint, "Paint", FALSE );
6127     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6128     check_update_rgn( hwnd, 0 );
6129
6130     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6131      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6132      */
6133     trace("testing ValidateRect(0, NULL)\n");
6134     SetRectEmpty( &rect );
6135     if (ValidateRect(0, &rect))  /* not supported on Win9x */
6136     {
6137         check_update_rgn( hwnd, hrgn );
6138         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6139         flush_events();
6140         ok_sequence( WmPaint, "Paint", FALSE );
6141         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6142         check_update_rgn( hwnd, 0 );
6143     }
6144
6145     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6146     SetLastError(0xdeadbeef);
6147     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6148     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6149        "wrong error code %d\n", GetLastError());
6150     check_update_rgn( hwnd, 0 );
6151     flush_events();
6152     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6153
6154     trace("testing ValidateRgn(0, NULL)\n");
6155     SetLastError(0xdeadbeef);
6156     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6157     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6158        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6159        "wrong error code %d\n", GetLastError());
6160     check_update_rgn( hwnd, 0 );
6161     flush_events();
6162     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6163
6164     trace("testing UpdateWindow(NULL)\n");
6165     SetLastError(0xdeadbeef);
6166     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6167     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6168        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6169        "wrong error code %d\n", GetLastError());
6170     check_update_rgn( hwnd, 0 );
6171     flush_events();
6172     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6173
6174     /* now with frame */
6175     SetRectRgn( hrgn, -5, -5, 20, 20 );
6176
6177     /* flush pending messages */
6178     flush_events();
6179     flush_sequence();
6180     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6181     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6182
6183     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
6184     check_update_rgn( hwnd, hrgn );
6185
6186     flush_sequence();
6187     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6188     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6189
6190     flush_sequence();
6191     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6192     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6193
6194     GetClientRect( hwnd, &rect );
6195     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6196     check_update_rgn( hwnd, hrgn );
6197
6198     flush_sequence();
6199     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6200     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6201
6202     flush_sequence();
6203     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6204     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6205     check_update_rgn( hwnd, 0 );
6206
6207     flush_sequence();
6208     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6209     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6210     check_update_rgn( hwnd, 0 );
6211
6212     flush_sequence();
6213     SetRectRgn( hrgn, 0, 0, 100, 100 );
6214     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6215     SetRectRgn( hrgn, 0, 0, 50, 100 );
6216     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6217     SetRectRgn( hrgn, 50, 0, 100, 100 );
6218     check_update_rgn( hwnd, hrgn );
6219     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6220     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
6221     check_update_rgn( hwnd, 0 );
6222
6223     flush_sequence();
6224     SetRectRgn( hrgn, 0, 0, 100, 100 );
6225     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6226     SetRectRgn( hrgn, 0, 0, 100, 50 );
6227     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6228     ok_sequence( WmErase, "Erase", FALSE );
6229     SetRectRgn( hrgn, 0, 50, 100, 100 );
6230     check_update_rgn( hwnd, hrgn );
6231
6232     flush_sequence();
6233     SetRectRgn( hrgn, 0, 0, 100, 100 );
6234     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6235     SetRectRgn( hrgn, 0, 0, 50, 50 );
6236     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6237     ok_sequence( WmPaint, "Paint", FALSE );
6238
6239     flush_sequence();
6240     SetRectRgn( hrgn, -4, -4, -2, -2 );
6241     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6242     SetRectRgn( hrgn, -200, -200, -198, -198 );
6243     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6244     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6245
6246     flush_sequence();
6247     SetRectRgn( hrgn, -4, -4, -2, -2 );
6248     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6249     SetRectRgn( hrgn, -4, -4, -3, -3 );
6250     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6251     SetRectRgn( hrgn, 0, 0, 1, 1 );
6252     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6253     ok_sequence( WmPaint, "Paint", FALSE );
6254
6255     flush_sequence();
6256     SetRectRgn( hrgn, -4, -4, -1, -1 );
6257     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6258     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6259     /* make sure no WM_PAINT was generated */
6260     flush_events();
6261     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6262
6263     flush_sequence();
6264     SetRectRgn( hrgn, -4, -4, -1, -1 );
6265     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6266     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6267     {
6268         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6269         {
6270             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6271             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6272             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6273             ret = GetUpdateRect( hwnd, &rect, FALSE );
6274             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6275             /* this will send WM_NCPAINT and validate the non client area */
6276             ret = GetUpdateRect( hwnd, &rect, TRUE );
6277             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6278         }
6279         DispatchMessage( &msg );
6280     }
6281     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6282
6283     DestroyWindow( hwnd );
6284
6285     /* now test with a child window */
6286
6287     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6288                               100, 100, 200, 200, 0, 0, 0, NULL);
6289     ok (hparent != 0, "Failed to create parent window\n");
6290
6291     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6292                            10, 10, 100, 100, hparent, 0, 0, NULL);
6293     ok (hchild != 0, "Failed to create child window\n");
6294
6295     ShowWindow( hparent, SW_SHOW );
6296     UpdateWindow( hparent );
6297     UpdateWindow( hchild );
6298     flush_events();
6299     flush_sequence();
6300     log_all_parent_messages++;
6301
6302     SetRect( &rect, 0, 0, 50, 50 );
6303     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6304     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6305     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6306
6307     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6308     pt.x = pt.y = 0;
6309     MapWindowPoints( hchild, hparent, &pt, 1 );
6310     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6311     check_update_rgn( hchild, hrgn );
6312     SetRectRgn( hrgn, 0, 0, 50, 50 );
6313     check_update_rgn( hparent, hrgn );
6314     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6315     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6316     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6317     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6318
6319     flush_events();
6320     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6321
6322     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6323     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6324     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6325     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6326     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6327
6328     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6329     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6330     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6331
6332     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6333     flush_sequence();
6334     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6335     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6336     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6337
6338     /* flush all paint messages */
6339     flush_events();
6340     flush_sequence();
6341
6342     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6343     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6344     SetRectRgn( hrgn, 0, 0, 50, 50 );
6345     check_update_rgn( hparent, hrgn );
6346     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6347     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6348     SetRectRgn( hrgn, 0, 0, 50, 50 );
6349     check_update_rgn( hparent, hrgn );
6350
6351     /* flush all paint messages */
6352     flush_events();
6353     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6354     flush_sequence();
6355
6356     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6357     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6358     SetRectRgn( hrgn, 0, 0, 50, 50 );
6359     check_update_rgn( hparent, hrgn );
6360     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6361     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6362     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6363     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6364     check_update_rgn( hparent, hrgn );
6365     /* flush all paint messages */
6366     flush_events();
6367     flush_sequence();
6368
6369     /* same as above but parent gets completely validated */
6370     SetRect( &rect, 20, 20, 30, 30 );
6371     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6372     SetRectRgn( hrgn, 20, 20, 30, 30 );
6373     check_update_rgn( hparent, hrgn );
6374     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6375     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6376     check_update_rgn( hparent, 0 );  /* no update region */
6377     flush_events();
6378     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6379
6380     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6381     flush_sequence();
6382     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6383     SetRectRgn( hrgn, 20, 20, 30, 30 );
6384     check_update_rgn( hparent, hrgn );
6385     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6386     SetRectRgn( hrgn, 20, 20, 30, 30 );
6387     check_update_rgn( hparent, hrgn );
6388
6389     /* same as above but normal WM_PAINT doesn't validate parent */
6390     flush_sequence();
6391     SetRect( &rect, 20, 20, 30, 30 );
6392     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6393     SetRectRgn( hrgn, 20, 20, 30, 30 );
6394     check_update_rgn( hparent, hrgn );
6395     /* no WM_PAINT in child while parent still pending */
6396     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6397     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6398     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6399     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6400
6401     flush_sequence();
6402     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6403     /* no WM_PAINT in child while parent still pending */
6404     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6405     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6406     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6407     /* now that parent is valid child should get WM_PAINT */
6408     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6409     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6410     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6411     ok_sequence( WmEmptySeq, "No other message", FALSE );
6412
6413     /* same thing with WS_CLIPCHILDREN in parent */
6414     flush_sequence();
6415     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6416     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6417     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6418     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6419     ok_sequence( WmEmptySeq, "No message", FALSE );
6420     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6421     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6422
6423     flush_sequence();
6424     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6425     SetRectRgn( hrgn, 20, 20, 30, 30 );
6426     check_update_rgn( hparent, hrgn );
6427     /* no WM_PAINT in child while parent still pending */
6428     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6429     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6430     /* WM_PAINT in parent first */
6431     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6432     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6433
6434     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6435     flush_sequence();
6436     SetRect( &rect, 0, 0, 30, 30 );
6437     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6438     SetRectRgn( hrgn, 0, 0, 30, 30 );
6439     check_update_rgn( hparent, hrgn );
6440     flush_events();
6441     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6442
6443     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6444     flush_sequence();
6445     SetRect( &rect, -10, 0, 30, 30 );
6446     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6447     SetRect( &rect, 0, 0, 20, 20 );
6448     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6449     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6450     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6451
6452     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6453     flush_sequence();
6454     SetRect( &rect, -10, 0, 30, 30 );
6455     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6456     SetRect( &rect, 0, 0, 100, 100 );
6457     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6458     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6459     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6460     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6461     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6462
6463     /* test RDW_INTERNALPAINT behavior */
6464
6465     flush_sequence();
6466     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6467     flush_events();
6468     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6469
6470     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6471     flush_events();
6472     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6473
6474     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6475     flush_events();
6476     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6477
6478     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6479     UpdateWindow( hparent );
6480     flush_events();
6481     flush_sequence();
6482     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6483     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6484     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6485                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6486     flush_events();
6487     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6488
6489     UpdateWindow( hparent );
6490     flush_events();
6491     flush_sequence();
6492     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6493     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6494     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6495                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6496     flush_events();
6497     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6498
6499     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6500     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6501     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6502     flush_events();
6503     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6504
6505     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6506     UpdateWindow( hparent );
6507     flush_events();
6508     flush_sequence();
6509     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6510     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6511     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6512                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6513     flush_events();
6514     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6515
6516     UpdateWindow( hparent );
6517     flush_events();
6518     flush_sequence();
6519     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6520     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6521     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6522                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6523     flush_events();
6524     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6525
6526     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6527     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6528
6529     UpdateWindow( hparent );
6530     flush_events();
6531     flush_sequence();
6532     trace("testing SetWindowPos(-10000, -10000) on child\n");
6533     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6534     check_update_rgn( hchild, 0 );
6535     flush_events();
6536
6537 #if 0 /* this one doesn't pass under Wine yet */
6538     UpdateWindow( hparent );
6539     flush_events();
6540     flush_sequence();
6541     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6542     ShowWindow( hchild, SW_MINIMIZE );
6543     check_update_rgn( hchild, 0 );
6544     flush_events();
6545 #endif
6546
6547     UpdateWindow( hparent );
6548     flush_events();
6549     flush_sequence();
6550     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6551     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6552     check_update_rgn( hparent, 0 );
6553     flush_events();
6554
6555     log_all_parent_messages--;
6556     DestroyWindow( hparent );
6557     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6558
6559     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6560
6561     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6562                               100, 100, 200, 200, 0, 0, 0, NULL);
6563     ok (hparent != 0, "Failed to create parent window\n");
6564
6565     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6566                            10, 10, 100, 100, hparent, 0, 0, NULL);
6567     ok (hchild != 0, "Failed to create child window\n");
6568
6569     ShowWindow( hparent, SW_SHOW );
6570     UpdateWindow( hparent );
6571     UpdateWindow( hchild );
6572     flush_events();
6573     flush_sequence();
6574
6575     /* moving child outside of parent boundaries changes update region */
6576     SetRect( &rect, 0, 0, 40, 40 );
6577     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6578     SetRectRgn( hrgn, 0, 0, 40, 40 );
6579     check_update_rgn( hchild, hrgn );
6580     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6581     SetRectRgn( hrgn, 10, 0, 40, 40 );
6582     check_update_rgn( hchild, hrgn );
6583     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6584     SetRectRgn( hrgn, 10, 10, 40, 40 );
6585     check_update_rgn( hchild, hrgn );
6586
6587     /* moving parent off-screen does too */
6588     SetRect( &rect, 0, 0, 100, 100 );
6589     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6590     SetRectRgn( hrgn, 0, 0, 100, 100 );
6591     check_update_rgn( hparent, hrgn );
6592     SetRectRgn( hrgn, 10, 10, 40, 40 );
6593     check_update_rgn( hchild, hrgn );
6594     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6595     SetRectRgn( hrgn, 20, 20, 100, 100 );
6596     check_update_rgn( hparent, hrgn );
6597     SetRectRgn( hrgn, 30, 30, 40, 40 );
6598     check_update_rgn( hchild, hrgn );
6599
6600     /* invalidated region is cropped by the parent rects */
6601     SetRect( &rect, 0, 0, 50, 50 );
6602     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6603     SetRectRgn( hrgn, 30, 30, 50, 50 );
6604     check_update_rgn( hchild, hrgn );
6605
6606     DestroyWindow( hparent );
6607     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6608     flush_sequence();
6609
6610     DeleteObject( hrgn );
6611     DeleteObject( hrgn2 );
6612 }
6613
6614 struct wnd_event
6615 {
6616     HWND hwnd;
6617     HANDLE grand_child;
6618     HANDLE start_event;
6619     HANDLE stop_event;
6620 };
6621
6622 static DWORD WINAPI thread_proc(void *param)
6623 {
6624     MSG msg;
6625     struct wnd_event *wnd_event = param;
6626
6627     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6628                                       100, 100, 200, 200, 0, 0, 0, NULL);
6629     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6630
6631     SetEvent(wnd_event->start_event);
6632
6633     while (GetMessage(&msg, 0, 0, 0))
6634     {
6635         TranslateMessage(&msg);
6636         DispatchMessage(&msg);
6637     }
6638
6639     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6640
6641     return 0;
6642 }
6643
6644 static DWORD CALLBACK create_grand_child_thread( void *param )
6645 {
6646     struct wnd_event *wnd_event = param;
6647     HWND hchild;
6648     MSG msg;
6649
6650     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6651                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6652     ok (hchild != 0, "Failed to create child window\n");
6653     flush_events();
6654     flush_sequence();
6655     SetEvent( wnd_event->start_event );
6656
6657     for (;;)
6658     {
6659         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6660         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6661         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6662     }
6663     return 0;
6664 }
6665
6666 static DWORD CALLBACK create_child_thread( void *param )
6667 {
6668     struct wnd_event *wnd_event = param;
6669     struct wnd_event child_event;
6670     DWORD ret, tid;
6671     MSG msg;
6672
6673     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6674                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6675     ok (child_event.hwnd != 0, "Failed to create child window\n");
6676     SetFocus( child_event.hwnd );
6677     flush_events();
6678     flush_sequence();
6679     child_event.start_event = wnd_event->start_event;
6680     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6681     for (;;)
6682     {
6683         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6684         if (ret != 1) break;
6685         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6686     }
6687     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6688     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6689     return 0;
6690 }
6691
6692 static void test_interthread_messages(void)
6693 {
6694     HANDLE hThread;
6695     DWORD tid;
6696     WNDPROC proc;
6697     MSG msg;
6698     char buf[256];
6699     int len, expected_len;
6700     struct wnd_event wnd_event;
6701     BOOL ret;
6702
6703     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6704     if (!wnd_event.start_event)
6705     {
6706         win_skip("skipping interthread message test under win9x\n");
6707         return;
6708     }
6709
6710     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6711     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6712
6713     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6714
6715     CloseHandle(wnd_event.start_event);
6716
6717     SetLastError(0xdeadbeef);
6718     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6719     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6720        "wrong error code %d\n", GetLastError());
6721
6722     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6723     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6724
6725     expected_len = lstrlenA("window caption text");
6726     memset(buf, 0, sizeof(buf));
6727     SetLastError(0xdeadbeef);
6728     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6729     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6730     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6731
6732     msg.hwnd = wnd_event.hwnd;
6733     msg.message = WM_GETTEXT;
6734     msg.wParam = sizeof(buf);
6735     msg.lParam = (LPARAM)buf;
6736     memset(buf, 0, sizeof(buf));
6737     SetLastError(0xdeadbeef);
6738     len = DispatchMessageA(&msg);
6739     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6740        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6741
6742     /* the following test causes an exception in user.exe under win9x */
6743     msg.hwnd = wnd_event.hwnd;
6744     msg.message = WM_TIMER;
6745     msg.wParam = 0;
6746     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6747     SetLastError(0xdeadbeef);
6748     len = DispatchMessageA(&msg);
6749     ok(!len && GetLastError() == 0xdeadbeef,
6750        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6751
6752     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6753     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6754
6755     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6756     CloseHandle(hThread);
6757
6758     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6759
6760     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6761                               100, 100, 200, 200, 0, 0, 0, NULL);
6762     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6763     flush_sequence();
6764     log_all_parent_messages++;
6765     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6766     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6767     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6768     for (;;)
6769     {
6770         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6771         if (ret != 1) break;
6772         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6773     }
6774     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6775     /* now wait for the thread without processing messages; this shouldn't deadlock */
6776     SetEvent( wnd_event.stop_event );
6777     ret = WaitForSingleObject( hThread, 5000 );
6778     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6779     CloseHandle( hThread );
6780
6781     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6782     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6783     CloseHandle( wnd_event.grand_child );
6784
6785     CloseHandle( wnd_event.start_event );
6786     CloseHandle( wnd_event.stop_event );
6787     flush_events();
6788     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6789     log_all_parent_messages--;
6790     DestroyWindow( wnd_event.hwnd );
6791 }
6792
6793
6794 static const struct message WmVkN[] = {
6795     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6796     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6797     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6798     { WM_CHAR, wparam|lparam, 'n', 1 },
6799     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6800     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6801     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6802     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6803     { 0 }
6804 };
6805 static const struct message WmShiftVkN[] = {
6806     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6807     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6808     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6809     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6810     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6811     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6812     { WM_CHAR, wparam|lparam, 'N', 1 },
6813     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6814     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6815     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6816     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6817     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6818     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6819     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6820     { 0 }
6821 };
6822 static const struct message WmCtrlVkN[] = {
6823     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6824     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6825     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6826     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6827     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6828     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6829     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6830     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6831     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6832     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6833     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6834     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6835     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6836     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6837     { 0 }
6838 };
6839 static const struct message WmCtrlVkN_2[] = {
6840     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6841     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6842     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6843     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6844     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6845     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6846     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6847     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6848     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6849     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6850     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6851     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6852     { 0 }
6853 };
6854 static const struct message WmAltVkN[] = {
6855     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6856     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6857     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6858     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6859     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6860     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6861     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6862     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6863     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6864     { HCBT_SYSCOMMAND, hook },
6865     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6866     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6867     { 0x00AE, sent|defwinproc|optional }, /* XP */
6868     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6869     { WM_INITMENU, sent|defwinproc },
6870     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6871     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6872     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6873     { WM_CAPTURECHANGED, sent|defwinproc },
6874     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6875     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6876     { WM_EXITMENULOOP, sent|defwinproc },
6877     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6878     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6879     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6880     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6881     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6882     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6883     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6884     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6885     { 0 }
6886 };
6887 static const struct message WmAltVkN_2[] = {
6888     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6889     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6890     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6891     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6892     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6893     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6894     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6895     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6896     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6897     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6898     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6899     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6900     { 0 }
6901 };
6902 static const struct message WmCtrlAltVkN[] = {
6903     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6904     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6905     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6906     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6907     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6908     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6909     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6910     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6911     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6912     { WM_CHAR, optional },
6913     { WM_CHAR, sent|optional },
6914     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6915     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6916     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6917     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6918     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6919     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6920     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6921     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6922     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6923     { 0 }
6924 };
6925 static const struct message WmCtrlShiftVkN[] = {
6926     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6927     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6928     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6929     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6930     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6931     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6932     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6933     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6934     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6935     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6936     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6937     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6938     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6939     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6940     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6941     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6942     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6943     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6944     { 0 }
6945 };
6946 static const struct message WmCtrlAltShiftVkN[] = {
6947     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6948     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6949     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6950     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6951     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6952     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6953     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6954     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6955     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6956     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6957     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6958     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6959     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6960     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6961     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6962     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6963     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6964     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6965     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6966     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6967     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6968     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6969     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6970     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6971     { 0 }
6972 };
6973 static const struct message WmAltPressRelease[] = {
6974     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6975     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6976     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6977     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6978     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6979     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6980     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6981     { HCBT_SYSCOMMAND, hook },
6982     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6983     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6984     { WM_INITMENU, sent|defwinproc },
6985     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6986     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6987     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6988
6989     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6990
6991     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6992     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6993     { WM_CAPTURECHANGED, sent|defwinproc },
6994     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6995     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6996     { WM_EXITMENULOOP, sent|defwinproc },
6997     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6998     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6999     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7000     { 0 }
7001 };
7002 static const struct message WmShiftMouseButton[] = {
7003     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7004     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7005     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7006     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7007     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7008     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7009     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7010     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7011     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7012     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7013     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7014     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7015     { 0 }
7016 };
7017 static const struct message WmF1Seq[] = {
7018     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7019     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7020     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7021     { WM_KEYF1, wparam|lparam, 0, 0 },
7022     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7023     { WM_HELP, sent|defwinproc },
7024     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7025     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7026     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7027     { 0 }
7028 };
7029 static const struct message WmVkAppsSeq[] = {
7030     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7031     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7032     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7033     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7034     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7035     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7036     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7037     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7038     { 0 }
7039 };
7040 static const struct message WmVkF10Seq[] = {
7041     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7042     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7043     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7044     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7045     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7046     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7047     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7048     { HCBT_SYSCOMMAND, hook },
7049     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7050     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7051     { WM_INITMENU, sent|defwinproc },
7052     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7053     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7054     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7055
7056     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7057
7058     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7059     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7060     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7061     { WM_CAPTURECHANGED, sent|defwinproc },
7062     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7063     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7064     { WM_EXITMENULOOP, sent|defwinproc },
7065     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7066     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7067     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7068     { 0 }
7069 };
7070 static const struct message WmShiftF10Seq[] = {
7071     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7072     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7073     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7074     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7075     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7076     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7077     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7078     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7079     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7080     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7081     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7082     { HCBT_SYSCOMMAND, hook },
7083     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7084     { WM_INITMENU, sent|defwinproc },
7085     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7086     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7087     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7088     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7089     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7090     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7091     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7092     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7093     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7094     { 0 }
7095 };
7096
7097 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7098 {
7099     MSG msg;
7100
7101     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7102     {
7103         struct recvd_message log_msg;
7104
7105         /* ignore some unwanted messages */
7106         if (msg.message == WM_MOUSEMOVE ||
7107             msg.message == WM_TIMER ||
7108             ignore_message( msg.message ))
7109             continue;
7110
7111         log_msg.hwnd = msg.hwnd;
7112         log_msg.message = msg.message;
7113         log_msg.flags = wparam|lparam;
7114         log_msg.wParam = msg.wParam;
7115         log_msg.lParam = msg.lParam;
7116         log_msg.descr = "accel";
7117         add_message(&log_msg);
7118
7119         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
7120         {
7121             TranslateMessage(&msg);
7122             DispatchMessage(&msg);
7123         }
7124     }
7125 }
7126
7127 static void test_accelerators(void)
7128 {
7129     RECT rc;
7130     POINT pt;
7131     SHORT state;
7132     HACCEL hAccel;
7133     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7134                                 100, 100, 200, 200, 0, 0, 0, NULL);
7135     BOOL ret;
7136
7137     assert(hwnd != 0);
7138     UpdateWindow(hwnd);
7139     flush_events();
7140     flush_sequence();
7141
7142     SetFocus(hwnd);
7143     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7144
7145     state = GetKeyState(VK_SHIFT);
7146     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7147     state = GetKeyState(VK_CAPITAL);
7148     ok(state == 0, "wrong CapsLock state %04x\n", state);
7149
7150     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
7151     assert(hAccel != 0);
7152
7153     flush_events();
7154     pump_msg_loop(hwnd, 0);
7155     flush_sequence();
7156
7157     trace("testing VK_N press/release\n");
7158     flush_sequence();
7159     keybd_event('N', 0, 0, 0);
7160     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7161     pump_msg_loop(hwnd, hAccel);
7162     if (!sequence_cnt)  /* we didn't get any message */
7163     {
7164         skip( "queuing key events not supported\n" );
7165         goto done;
7166     }
7167     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7168
7169     trace("testing Shift+VK_N press/release\n");
7170     flush_sequence();
7171     keybd_event(VK_SHIFT, 0, 0, 0);
7172     keybd_event('N', 0, 0, 0);
7173     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7174     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7175     pump_msg_loop(hwnd, hAccel);
7176     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7177
7178     trace("testing Ctrl+VK_N press/release\n");
7179     flush_sequence();
7180     keybd_event(VK_CONTROL, 0, 0, 0);
7181     keybd_event('N', 0, 0, 0);
7182     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7183     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7184     pump_msg_loop(hwnd, hAccel);
7185     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7186
7187     trace("testing Alt+VK_N press/release\n");
7188     flush_sequence();
7189     keybd_event(VK_MENU, 0, 0, 0);
7190     keybd_event('N', 0, 0, 0);
7191     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7192     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7193     pump_msg_loop(hwnd, hAccel);
7194     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7195
7196     trace("testing Ctrl+Alt+VK_N press/release 1\n");
7197     flush_sequence();
7198     keybd_event(VK_CONTROL, 0, 0, 0);
7199     keybd_event(VK_MENU, 0, 0, 0);
7200     keybd_event('N', 0, 0, 0);
7201     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7202     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7203     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7204     pump_msg_loop(hwnd, hAccel);
7205     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7206
7207     ret = DestroyAcceleratorTable(hAccel);
7208     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7209
7210     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
7211     assert(hAccel != 0);
7212
7213     trace("testing VK_N press/release\n");
7214     flush_sequence();
7215     keybd_event('N', 0, 0, 0);
7216     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7217     pump_msg_loop(hwnd, hAccel);
7218     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7219
7220     trace("testing Shift+VK_N press/release\n");
7221     flush_sequence();
7222     keybd_event(VK_SHIFT, 0, 0, 0);
7223     keybd_event('N', 0, 0, 0);
7224     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7225     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7226     pump_msg_loop(hwnd, hAccel);
7227     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7228
7229     trace("testing Ctrl+VK_N press/release 2\n");
7230     flush_sequence();
7231     keybd_event(VK_CONTROL, 0, 0, 0);
7232     keybd_event('N', 0, 0, 0);
7233     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7234     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7235     pump_msg_loop(hwnd, hAccel);
7236     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7237
7238     trace("testing Alt+VK_N press/release 2\n");
7239     flush_sequence();
7240     keybd_event(VK_MENU, 0, 0, 0);
7241     keybd_event('N', 0, 0, 0);
7242     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7243     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7244     pump_msg_loop(hwnd, hAccel);
7245     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7246
7247     trace("testing Ctrl+Alt+VK_N press/release 2\n");
7248     flush_sequence();
7249     keybd_event(VK_CONTROL, 0, 0, 0);
7250     keybd_event(VK_MENU, 0, 0, 0);
7251     keybd_event('N', 0, 0, 0);
7252     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7253     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7254     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7255     pump_msg_loop(hwnd, hAccel);
7256     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7257
7258     trace("testing Ctrl+Shift+VK_N press/release\n");
7259     flush_sequence();
7260     keybd_event(VK_CONTROL, 0, 0, 0);
7261     keybd_event(VK_SHIFT, 0, 0, 0);
7262     keybd_event('N', 0, 0, 0);
7263     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7264     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7265     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7266     pump_msg_loop(hwnd, hAccel);
7267     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7268
7269     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7270     flush_sequence();
7271     keybd_event(VK_CONTROL, 0, 0, 0);
7272     keybd_event(VK_MENU, 0, 0, 0);
7273     keybd_event(VK_SHIFT, 0, 0, 0);
7274     keybd_event('N', 0, 0, 0);
7275     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7276     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7277     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7278     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7279     pump_msg_loop(hwnd, hAccel);
7280     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7281
7282     ret = DestroyAcceleratorTable(hAccel);
7283     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7284     hAccel = 0;
7285
7286     trace("testing Alt press/release\n");
7287     flush_sequence();
7288     keybd_event(VK_MENU, 0, 0, 0);
7289     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7290     keybd_event(VK_MENU, 0, 0, 0);
7291     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7292     pump_msg_loop(hwnd, 0);
7293     /* this test doesn't pass in Wine for managed windows */
7294     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7295
7296     trace("testing VK_F1 press/release\n");
7297     keybd_event(VK_F1, 0, 0, 0);
7298     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7299     pump_msg_loop(hwnd, 0);
7300     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7301
7302     trace("testing VK_APPS press/release\n");
7303     keybd_event(VK_APPS, 0, 0, 0);
7304     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7305     pump_msg_loop(hwnd, 0);
7306     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7307
7308     trace("testing VK_F10 press/release\n");
7309     keybd_event(VK_F10, 0, 0, 0);
7310     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7311     keybd_event(VK_F10, 0, 0, 0);
7312     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7313     pump_msg_loop(hwnd, 0);
7314     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7315
7316     trace("testing SHIFT+F10 press/release\n");
7317     keybd_event(VK_SHIFT, 0, 0, 0);
7318     keybd_event(VK_F10, 0, 0, 0);
7319     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7320     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7321     keybd_event(VK_ESCAPE, 0, 0, 0);
7322     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7323     pump_msg_loop(hwnd, 0);
7324     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7325
7326     trace("testing Shift+MouseButton press/release\n");
7327     /* first, move mouse pointer inside of the window client area */
7328     GetClientRect(hwnd, &rc);
7329     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7330     rc.left += (rc.right - rc.left)/2;
7331     rc.top += (rc.bottom - rc.top)/2;
7332     SetCursorPos(rc.left, rc.top);
7333     SetActiveWindow(hwnd);
7334
7335     flush_events();
7336     flush_sequence();
7337     GetCursorPos(&pt);
7338     if (pt.x == rc.left && pt.y == rc.top)
7339     {
7340         int i;
7341         keybd_event(VK_SHIFT, 0, 0, 0);
7342         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7343         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7344         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7345         pump_msg_loop(hwnd, 0);
7346         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7347         if (i < sequence_cnt)
7348             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7349         else
7350             skip( "Shift+MouseButton event didn't get to the window\n" );
7351     }
7352
7353 done:
7354     if (hAccel) DestroyAcceleratorTable(hAccel);
7355     DestroyWindow(hwnd);
7356 }
7357
7358 /************* window procedures ********************/
7359
7360 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
7361                              WPARAM wParam, LPARAM lParam)
7362 {
7363     static LONG defwndproc_counter = 0;
7364     static LONG beginpaint_counter = 0;
7365     LRESULT ret;
7366     struct recvd_message msg;
7367
7368     if (ignore_message( message )) return 0;
7369
7370     switch (message)
7371     {
7372         case WM_ENABLE:
7373         {
7374             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7375             ok((BOOL)wParam == !(style & WS_DISABLED),
7376                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7377             break;
7378         }
7379
7380         case WM_CAPTURECHANGED:
7381             if (test_DestroyWindow_flag)
7382             {
7383                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7384                 if (style & WS_CHILD)
7385                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7386                 else if (style & WS_POPUP)
7387                     lParam = WND_POPUP_ID;
7388                 else
7389                     lParam = WND_PARENT_ID;
7390             }
7391             break;
7392
7393         case WM_NCDESTROY:
7394         {
7395             HWND capture;
7396
7397             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7398             capture = GetCapture();
7399             if (capture)
7400             {
7401                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7402                 trace("current capture %p, releasing...\n", capture);
7403                 ReleaseCapture();
7404             }
7405         }
7406         /* fall through */
7407         case WM_DESTROY:
7408             if (pGetAncestor)
7409                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7410             if (test_DestroyWindow_flag)
7411             {
7412                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7413                 if (style & WS_CHILD)
7414                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7415                 else if (style & WS_POPUP)
7416                     lParam = WND_POPUP_ID;
7417                 else
7418                     lParam = WND_PARENT_ID;
7419             }
7420             break;
7421
7422         /* test_accelerators() depends on this */
7423         case WM_NCHITTEST:
7424             return HTCLIENT;
7425
7426         /* ignore */
7427         case WM_MOUSEMOVE:
7428         case WM_MOUSEACTIVATE:
7429         case WM_NCMOUSEMOVE:
7430         case WM_SETCURSOR:
7431         case WM_IME_SELECT:
7432             return 0;
7433     }
7434
7435     msg.hwnd = hwnd;
7436     msg.message = message;
7437     msg.flags = sent|wparam|lparam;
7438     if (defwndproc_counter) msg.flags |= defwinproc;
7439     if (beginpaint_counter) msg.flags |= beginpaint;
7440     msg.wParam = wParam;
7441     msg.lParam = lParam;
7442     msg.descr = "MsgCheckProc";
7443     add_message(&msg);
7444
7445     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7446     {
7447         HWND parent = GetParent(hwnd);
7448         RECT rc;
7449         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7450
7451         GetClientRect(parent, &rc);
7452         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7453         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7454               minmax->ptReserved.x, minmax->ptReserved.y,
7455               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7456               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7457               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7458               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7459
7460         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7461            minmax->ptMaxSize.x, rc.right);
7462         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7463            minmax->ptMaxSize.y, rc.bottom);
7464     }
7465
7466     if (message == WM_PAINT)
7467     {
7468         PAINTSTRUCT ps;
7469         beginpaint_counter++;
7470         BeginPaint( hwnd, &ps );
7471         beginpaint_counter--;
7472         EndPaint( hwnd, &ps );
7473         return 0;
7474     }
7475
7476     defwndproc_counter++;
7477     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7478                   : DefWindowProcA(hwnd, message, wParam, lParam);
7479     defwndproc_counter--;
7480
7481     return ret;
7482 }
7483
7484 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7485 {
7486     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7487 }
7488
7489 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7490 {
7491     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7492 }
7493
7494 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7495 {
7496     static LONG defwndproc_counter = 0;
7497     LRESULT ret;
7498     struct recvd_message msg;
7499
7500     if (ignore_message( message )) return 0;
7501
7502     switch (message)
7503     {
7504     case WM_QUERYENDSESSION:
7505     case WM_ENDSESSION:
7506         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7507         break;
7508     }
7509
7510     msg.hwnd = hwnd;
7511     msg.message = message;
7512     msg.flags = sent|wparam|lparam;
7513     if (defwndproc_counter) msg.flags |= defwinproc;
7514     msg.wParam = wParam;
7515     msg.lParam = lParam;
7516     msg.descr = "popup";
7517     add_message(&msg);
7518
7519     if (message == WM_CREATE)
7520     {
7521         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7522         SetWindowLongA(hwnd, GWL_STYLE, style);
7523     }
7524
7525     defwndproc_counter++;
7526     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7527     defwndproc_counter--;
7528
7529     return ret;
7530 }
7531
7532 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7533 {
7534     static LONG defwndproc_counter = 0;
7535     static LONG beginpaint_counter = 0;
7536     LRESULT ret;
7537     struct recvd_message msg;
7538
7539     if (ignore_message( message )) return 0;
7540
7541     if (log_all_parent_messages ||
7542         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7543         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7544         message == WM_ENABLE || message == WM_ENTERIDLE ||
7545         message == WM_DRAWITEM || message == WM_COMMAND ||
7546         message == WM_IME_SETCONTEXT)
7547     {
7548         switch (message)
7549         {
7550             /* ignore */
7551             case WM_NCHITTEST:
7552                 return HTCLIENT;
7553             case WM_SETCURSOR:
7554             case WM_MOUSEMOVE:
7555             case WM_NCMOUSEMOVE:
7556                 return 0;
7557
7558             case WM_ERASEBKGND:
7559             {
7560                 RECT rc;
7561                 INT ret = GetClipBox((HDC)wParam, &rc);
7562
7563                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7564                        ret, rc.left, rc.top, rc.right, rc.bottom);
7565                 break;
7566             }
7567         }
7568
7569         msg.hwnd = hwnd;
7570         msg.message = message;
7571         msg.flags = sent|parent|wparam|lparam;
7572         if (defwndproc_counter) msg.flags |= defwinproc;
7573         if (beginpaint_counter) msg.flags |= beginpaint;
7574         msg.wParam = wParam;
7575         msg.lParam = lParam;
7576         msg.descr = "parent";
7577         add_message(&msg);
7578     }
7579
7580     if (message == WM_PAINT)
7581     {
7582         PAINTSTRUCT ps;
7583         beginpaint_counter++;
7584         BeginPaint( hwnd, &ps );
7585         beginpaint_counter--;
7586         EndPaint( hwnd, &ps );
7587         return 0;
7588     }
7589
7590     defwndproc_counter++;
7591     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7592     defwndproc_counter--;
7593
7594     return ret;
7595 }
7596
7597 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7598 {
7599     static LONG defwndproc_counter = 0;
7600     LRESULT ret;
7601     struct recvd_message msg;
7602
7603     if (ignore_message( message )) return 0;
7604
7605     if (test_def_id)
7606     {
7607         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7608         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7609         if (after_end_dialog)
7610             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7611         else
7612             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7613     }
7614
7615     msg.hwnd = hwnd;
7616     msg.message = message;
7617     msg.flags = sent|wparam|lparam;
7618     if (defwndproc_counter) msg.flags |= defwinproc;
7619     msg.wParam = wParam;
7620     msg.lParam = lParam;
7621     msg.descr = "dialog";
7622     add_message(&msg);
7623
7624     defwndproc_counter++;
7625     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7626     defwndproc_counter--;
7627
7628     return ret;
7629 }
7630
7631 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7632 {
7633     static LONG defwndproc_counter = 0;
7634     LRESULT ret;
7635     struct recvd_message msg;
7636
7637     /* log only specific messages we are interested in */
7638     switch (message)
7639     {
7640 #if 0 /* probably log these as well */
7641     case WM_ACTIVATE:
7642     case WM_SETFOCUS:
7643     case WM_KILLFOCUS:
7644 #endif
7645     case WM_SHOWWINDOW:
7646     case WM_SIZE:
7647     case WM_MOVE:
7648     case WM_GETMINMAXINFO:
7649     case WM_WINDOWPOSCHANGING:
7650     case WM_WINDOWPOSCHANGED:
7651         break;
7652
7653     default: /* ignore */
7654         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7655         return DefWindowProcA(hwnd, message, wParam, lParam);
7656     }
7657
7658     msg.hwnd = hwnd;
7659     msg.message = message;
7660     msg.flags = sent|wparam|lparam;
7661     if (defwndproc_counter) msg.flags |= defwinproc;
7662     msg.wParam = wParam;
7663     msg.lParam = lParam;
7664     msg.descr = "show";
7665     add_message(&msg);
7666
7667     defwndproc_counter++;
7668     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7669     defwndproc_counter--;
7670
7671     return ret;
7672 }
7673
7674 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7675 {
7676     switch (msg)
7677     {
7678         case WM_CREATE: return 0;
7679         case WM_PAINT:
7680         {
7681             MSG msg2;
7682             static int i = 0;
7683
7684             if (i < 256)
7685             {
7686                 i++;
7687                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7688                 {
7689                     TranslateMessage(&msg2);
7690                     DispatchMessage(&msg2);
7691                 }
7692                 i--;
7693             }
7694             else ok(broken(1), "infinite loop\n");
7695             if ( i == 0)
7696                 paint_loop_done = 1;
7697             return DefWindowProcA(hWnd,msg,wParam,lParam);
7698         }
7699     }
7700     return DefWindowProcA(hWnd,msg,wParam,lParam);
7701 }
7702
7703 static BOOL RegisterWindowClasses(void)
7704 {
7705     WNDCLASSA cls;
7706     WNDCLASSW clsW;
7707
7708     cls.style = 0;
7709     cls.lpfnWndProc = MsgCheckProcA;
7710     cls.cbClsExtra = 0;
7711     cls.cbWndExtra = 0;
7712     cls.hInstance = GetModuleHandleA(0);
7713     cls.hIcon = 0;
7714     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7715     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7716     cls.lpszMenuName = NULL;
7717     cls.lpszClassName = "TestWindowClass";
7718     if(!RegisterClassA(&cls)) return FALSE;
7719
7720     cls.lpfnWndProc = ShowWindowProcA;
7721     cls.lpszClassName = "ShowWindowClass";
7722     if(!RegisterClassA(&cls)) return FALSE;
7723
7724     cls.lpfnWndProc = PopupMsgCheckProcA;
7725     cls.lpszClassName = "TestPopupClass";
7726     if(!RegisterClassA(&cls)) return FALSE;
7727
7728     cls.lpfnWndProc = ParentMsgCheckProcA;
7729     cls.lpszClassName = "TestParentClass";
7730     if(!RegisterClassA(&cls)) return FALSE;
7731
7732     cls.lpfnWndProc = DefWindowProcA;
7733     cls.lpszClassName = "SimpleWindowClass";
7734     if(!RegisterClassA(&cls)) return FALSE;
7735
7736     cls.lpfnWndProc = PaintLoopProcA;
7737     cls.lpszClassName = "PaintLoopWindowClass";
7738     if(!RegisterClassA(&cls)) return FALSE;
7739
7740     cls.style = CS_NOCLOSE;
7741     cls.lpszClassName = "NoCloseWindowClass";
7742     if(!RegisterClassA(&cls)) return FALSE;
7743
7744     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7745     cls.style = 0;
7746     cls.hInstance = GetModuleHandleA(0);
7747     cls.hbrBackground = 0;
7748     cls.lpfnWndProc = TestDlgProcA;
7749     cls.lpszClassName = "TestDialogClass";
7750     if(!RegisterClassA(&cls)) return FALSE;
7751
7752     clsW.style = 0;
7753     clsW.lpfnWndProc = MsgCheckProcW;
7754     clsW.cbClsExtra = 0;
7755     clsW.cbWndExtra = 0;
7756     clsW.hInstance = GetModuleHandleW(0);
7757     clsW.hIcon = 0;
7758     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7759     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7760     clsW.lpszMenuName = NULL;
7761     clsW.lpszClassName = testWindowClassW;
7762     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7763
7764     return TRUE;
7765 }
7766
7767 static BOOL is_our_logged_class(HWND hwnd)
7768 {
7769     char buf[256];
7770
7771     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7772     {
7773         if (!lstrcmpiA(buf, "TestWindowClass") ||
7774             !lstrcmpiA(buf, "ShowWindowClass") ||
7775             !lstrcmpiA(buf, "TestParentClass") ||
7776             !lstrcmpiA(buf, "TestPopupClass") ||
7777             !lstrcmpiA(buf, "SimpleWindowClass") ||
7778             !lstrcmpiA(buf, "TestDialogClass") ||
7779             !lstrcmpiA(buf, "MDI_frame_class") ||
7780             !lstrcmpiA(buf, "MDI_client_class") ||
7781             !lstrcmpiA(buf, "MDI_child_class") ||
7782             !lstrcmpiA(buf, "my_button_class") ||
7783             !lstrcmpiA(buf, "my_edit_class") ||
7784             !lstrcmpiA(buf, "static") ||
7785             !lstrcmpiA(buf, "ListBox") ||
7786             !lstrcmpiA(buf, "ComboBox") ||
7787             !lstrcmpiA(buf, "MyDialogClass") ||
7788             !lstrcmpiA(buf, "#32770") ||
7789             !lstrcmpiA(buf, "#32768"))
7790         return TRUE;
7791     }
7792     return FALSE;
7793 }
7794
7795 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7796
7797     HWND hwnd;
7798
7799     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7800
7801     if (nCode == HCBT_CLICKSKIPPED)
7802     {
7803         /* ignore this event, XP sends it a lot when switching focus between windows */
7804         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7805     }
7806
7807     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7808     {
7809         struct recvd_message msg;
7810
7811         msg.hwnd = 0;
7812         msg.message = nCode;
7813         msg.flags = hook|wparam|lparam;
7814         msg.wParam = wParam;
7815         msg.lParam = lParam;
7816         msg.descr = "CBT";
7817         add_message(&msg);
7818
7819         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7820     }
7821
7822     if (nCode == HCBT_DESTROYWND)
7823     {
7824         if (test_DestroyWindow_flag)
7825         {
7826             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7827             if (style & WS_CHILD)
7828                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7829             else if (style & WS_POPUP)
7830                 lParam = WND_POPUP_ID;
7831             else
7832                 lParam = WND_PARENT_ID;
7833         }
7834     }
7835
7836     /* Log also SetFocus(0) calls */
7837     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7838
7839     if (is_our_logged_class(hwnd))
7840     {
7841         struct recvd_message msg;
7842
7843         msg.hwnd = hwnd;
7844         msg.message = nCode;
7845         msg.flags = hook|wparam|lparam;
7846         msg.wParam = wParam;
7847         msg.lParam = lParam;
7848         msg.descr = "CBT";
7849         add_message(&msg);
7850     }
7851     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7852 }
7853
7854 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7855                                     DWORD event,
7856                                     HWND hwnd,
7857                                     LONG object_id,
7858                                     LONG child_id,
7859                                     DWORD thread_id,
7860                                     DWORD event_time)
7861 {
7862     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7863
7864     /* ignore mouse cursor events */
7865     if (object_id == OBJID_CURSOR) return;
7866
7867     if (!hwnd || is_our_logged_class(hwnd))
7868     {
7869         struct recvd_message msg;
7870
7871         msg.hwnd = hwnd;
7872         msg.message = event;
7873         msg.flags = winevent_hook|wparam|lparam;
7874         msg.wParam = object_id;
7875         msg.lParam = child_id;
7876         msg.descr = "WEH";
7877         add_message(&msg);
7878     }
7879 }
7880
7881 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7882 static const WCHAR wszAnsi[] = {'U',0};
7883
7884 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7885 {
7886     switch (uMsg)
7887     {
7888     case CB_FINDSTRINGEXACT:
7889         trace("String: %p\n", (LPCWSTR)lParam);
7890         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7891             return 1;
7892         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7893             return 0;
7894         return -1;
7895     }
7896     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7897 }
7898
7899 static const struct message WmGetTextLengthAfromW[] = {
7900     { WM_GETTEXTLENGTH, sent },
7901     { WM_GETTEXT, sent|optional },
7902     { 0 }
7903 };
7904
7905 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7906
7907 /* dummy window proc for WM_GETTEXTLENGTH test */
7908 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7909 {
7910     switch(msg)
7911     {
7912     case WM_GETTEXTLENGTH:
7913         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7914     case WM_GETTEXT:
7915         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7916         return lstrlenW( (LPWSTR)lp );
7917     default:
7918         return DefWindowProcW( hwnd, msg, wp, lp );
7919     }
7920 }
7921
7922 static void test_message_conversion(void)
7923 {
7924     static const WCHAR wszMsgConversionClass[] =
7925         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7926     WNDCLASSW cls;
7927     LRESULT lRes;
7928     HWND hwnd;
7929     WNDPROC wndproc, newproc;
7930     BOOL ret;
7931
7932     cls.style = 0;
7933     cls.lpfnWndProc = MsgConversionProcW;
7934     cls.cbClsExtra = 0;
7935     cls.cbWndExtra = 0;
7936     cls.hInstance = GetModuleHandleW(NULL);
7937     cls.hIcon = NULL;
7938     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7939     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7940     cls.lpszMenuName = NULL;
7941     cls.lpszClassName = wszMsgConversionClass;
7942     /* this call will fail on Win9x, but that doesn't matter as this test is
7943      * meaningless on those platforms */
7944     if(!RegisterClassW(&cls)) return;
7945
7946     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7947                            100, 100, 200, 200, 0, 0, 0, NULL);
7948     ok(hwnd != NULL, "Window creation failed\n");
7949
7950     /* {W, A} -> A */
7951
7952     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7953     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7954     ok(lRes == 0, "String should have been converted\n");
7955     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7956     ok(lRes == 1, "String shouldn't have been converted\n");
7957
7958     /* {W, A} -> W */
7959
7960     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7961     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7962     ok(lRes == 1, "String shouldn't have been converted\n");
7963     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7964     ok(lRes == 1, "String shouldn't have been converted\n");
7965
7966     /* Synchronous messages */
7967
7968     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7969     ok(lRes == 0, "String should have been converted\n");
7970     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7971     ok(lRes == 1, "String shouldn't have been converted\n");
7972
7973     /* Asynchronous messages */
7974
7975     SetLastError(0);
7976     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7977     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7978         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7979     SetLastError(0);
7980     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7981     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7982         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7983     SetLastError(0);
7984     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7985     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7986         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7987     SetLastError(0);
7988     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7989     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7990         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7991     SetLastError(0);
7992     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7993     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7994         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7995     SetLastError(0);
7996     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7997     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7998         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7999     SetLastError(0);
8000     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8001     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8002         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8003     SetLastError(0);
8004     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8005     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8006         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8007
8008     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8009
8010     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8011                           WS_OVERLAPPEDWINDOW,
8012                           100, 100, 200, 200, 0, 0, 0, NULL);
8013     assert(hwnd);
8014     flush_sequence();
8015     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8016     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8017     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8018         "got bad length %ld\n", lRes );
8019
8020     flush_sequence();
8021     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8022                             hwnd, WM_GETTEXTLENGTH, 0, 0);
8023     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8024     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8025         "got bad length %ld\n", lRes );
8026
8027     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8028     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8029     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8030     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8031                                      NULL, 0, NULL, NULL ) ||
8032         broken(lRes == lstrlenW(dummy_window_text) + 37),
8033         "got bad length %ld\n", lRes );
8034
8035     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
8036     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8037     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8038                                      NULL, 0, NULL, NULL ) ||
8039         broken(lRes == lstrlenW(dummy_window_text) + 37),
8040         "got bad length %ld\n", lRes );
8041
8042     ret = DestroyWindow(hwnd);
8043     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8044 }
8045
8046 struct timer_info
8047 {
8048     HWND hWnd;
8049     HANDLE handles[2];
8050     DWORD id;
8051 };
8052
8053 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8054 {
8055 }
8056
8057 static VOID CALLBACK tfunc_crash(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8058 {
8059     /* Crash on purpose */
8060     *(volatile int *)0 = 2;
8061 }
8062
8063 #define TIMER_ID  0x19
8064
8065 static DWORD WINAPI timer_thread_proc(LPVOID x)
8066 {
8067     struct timer_info *info = x;
8068     DWORD r;
8069
8070     r = KillTimer(info->hWnd, 0x19);
8071     ok(r,"KillTimer failed in thread\n");
8072     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8073     ok(r,"SetTimer failed in thread\n");
8074     ok(r==TIMER_ID,"SetTimer id different\n");
8075     r = SetEvent(info->handles[0]);
8076     ok(r,"SetEvent failed in thread\n");
8077     return 0;
8078 }
8079
8080 static void test_timers(void)
8081 {
8082     struct timer_info info;
8083     DWORD id;
8084     MSG msg;
8085
8086     info.hWnd = CreateWindow ("TestWindowClass", NULL,
8087        WS_OVERLAPPEDWINDOW ,
8088        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8089        NULL, NULL, 0);
8090
8091     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8092     ok(info.id, "SetTimer failed\n");
8093     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8094     info.handles[0] = CreateEvent(NULL,0,0,NULL);
8095     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8096
8097     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8098
8099     WaitForSingleObject(info.handles[1], INFINITE);
8100
8101     CloseHandle(info.handles[0]);
8102     CloseHandle(info.handles[1]);
8103
8104     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8105
8106     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8107
8108     /* Test timer callback with crash */
8109     SetLastError(0xdeadbeef);
8110     info.hWnd = CreateWindowW(testWindowClassW, NULL,
8111                               WS_OVERLAPPEDWINDOW ,
8112                               CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8113                               NULL, NULL, 0);
8114     if ((!info.hWnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || /* Win9x/Me */
8115         (!pGetMenuInfo)) /* Win95/NT4 */
8116     {
8117         win_skip("Test would crash on Win9x/WinMe/NT4\n");
8118         DestroyWindow(info.hWnd);
8119         return;
8120     }
8121     info.id = SetTimer(info.hWnd, TIMER_ID, 0, tfunc_crash);
8122     ok(info.id, "SetTimer failed\n");
8123     Sleep(150);
8124     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8125
8126     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8127 }
8128
8129 static int count = 0;
8130 static VOID CALLBACK callback_count(
8131     HWND hwnd,
8132     UINT uMsg,
8133     UINT_PTR idEvent,
8134     DWORD dwTime
8135 )
8136 {
8137     count++;
8138 }
8139
8140 static void test_timers_no_wnd(void)
8141 {
8142     UINT_PTR id, id2;
8143     MSG msg;
8144
8145     count = 0;
8146     id = SetTimer(NULL, 0, 100, callback_count);
8147     ok(id != 0, "did not get id from SetTimer.\n");
8148     id2 = SetTimer(NULL, id, 200, callback_count);
8149     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8150     Sleep(150);
8151     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8152     ok(count == 0, "did not get zero count as expected (%i).\n", count);
8153     Sleep(150);
8154     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8155     ok(count == 1, "did not get one count as expected (%i).\n", count);
8156     KillTimer(NULL, id);
8157     Sleep(250);
8158     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8159     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8160 }
8161
8162 /* Various win events with arbitrary parameters */
8163 static const struct message WmWinEventsSeq[] = {
8164     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8165     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8166     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8167     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8168     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8169     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8170     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8171     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8172     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8173     /* our win event hook ignores OBJID_CURSOR events */
8174     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8175     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8176     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8177     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8178     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8179     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8180     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8181     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8182     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8183     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8184     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8185     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8186     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8187     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8188     { 0 }
8189 };
8190 static const struct message WmWinEventCaretSeq[] = {
8191     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8192     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8193     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8194     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8195     { 0 }
8196 };
8197 static const struct message WmWinEventCaretSeq_2[] = {
8198     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8199     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8200     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8201     { 0 }
8202 };
8203 static const struct message WmWinEventAlertSeq[] = {
8204     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8205     { 0 }
8206 };
8207 static const struct message WmWinEventAlertSeq_2[] = {
8208     /* create window in the thread proc */
8209     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8210     /* our test event */
8211     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8212     { 0 }
8213 };
8214 static const struct message WmGlobalHookSeq_1[] = {
8215     /* create window in the thread proc */
8216     { HCBT_CREATEWND, hook|lparam, 0, 2 },
8217     /* our test events */
8218     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8219     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8220     { 0 }
8221 };
8222 static const struct message WmGlobalHookSeq_2[] = {
8223     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8224     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8225     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8226     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8227     { 0 }
8228 };
8229
8230 static const struct message WmMouseLLHookSeq[] = {
8231     { WM_MOUSEMOVE, hook },
8232     { WM_LBUTTONUP, hook },
8233     { WM_MOUSEMOVE, hook },
8234     { 0 }
8235 };
8236
8237 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8238                                          DWORD event,
8239                                          HWND hwnd,
8240                                          LONG object_id,
8241                                          LONG child_id,
8242                                          DWORD thread_id,
8243                                          DWORD event_time)
8244 {
8245     char buf[256];
8246
8247     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8248     {
8249         if (!lstrcmpiA(buf, "TestWindowClass") ||
8250             !lstrcmpiA(buf, "static"))
8251         {
8252             struct recvd_message msg;
8253
8254             msg.hwnd = hwnd;
8255             msg.message = event;
8256             msg.flags = winevent_hook|wparam|lparam;
8257             msg.wParam = object_id;
8258             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8259             msg.descr = "WEH_2";
8260             add_message(&msg);
8261         }
8262     }
8263 }
8264
8265 static HHOOK hCBT_global_hook;
8266 static DWORD cbt_global_hook_thread_id;
8267
8268 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
8269
8270     HWND hwnd;
8271     char buf[256];
8272
8273     if (nCode == HCBT_SYSCOMMAND)
8274     {
8275         struct recvd_message msg;
8276
8277         msg.hwnd = 0;
8278         msg.message = nCode;
8279         msg.flags = hook|wparam|lparam;
8280         msg.wParam = wParam;
8281         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8282         msg.descr = "CBT_2";
8283         add_message(&msg);
8284
8285         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8286     }
8287     /* WH_MOUSE_LL hook */
8288     if (nCode == HC_ACTION)
8289     {
8290         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8291
8292         /* we can't test for real mouse events */
8293         if (mhll->flags & LLMHF_INJECTED)
8294         {
8295             struct recvd_message msg;
8296
8297             memset (&msg, 0, sizeof (msg));
8298             msg.message = wParam;
8299             msg.flags = hook;
8300             msg.descr = "CBT_2";
8301             add_message(&msg);
8302         }
8303         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8304     }
8305
8306     /* Log also SetFocus(0) calls */
8307     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8308
8309     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8310     {
8311         if (!lstrcmpiA(buf, "TestWindowClass") ||
8312             !lstrcmpiA(buf, "static"))
8313         {
8314             struct recvd_message msg;
8315
8316             msg.hwnd = hwnd;
8317             msg.message = nCode;
8318             msg.flags = hook|wparam|lparam;
8319             msg.wParam = wParam;
8320             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8321             msg.descr = "CBT_2";
8322             add_message(&msg);
8323         }
8324     }
8325     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8326 }
8327
8328 static DWORD WINAPI win_event_global_thread_proc(void *param)
8329 {
8330     HWND hwnd;
8331     MSG msg;
8332     HANDLE hevent = *(HANDLE *)param;
8333
8334     assert(pNotifyWinEvent);
8335
8336     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8337     assert(hwnd);
8338     trace("created thread window %p\n", hwnd);
8339
8340     *(HWND *)param = hwnd;
8341
8342     flush_sequence();
8343     /* this event should be received only by our new hook proc,
8344      * an old one does not expect an event from another thread.
8345      */
8346     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8347     SetEvent(hevent);
8348
8349     while (GetMessage(&msg, 0, 0, 0))
8350     {
8351         TranslateMessage(&msg);
8352         DispatchMessage(&msg);
8353     }
8354     return 0;
8355 }
8356
8357 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8358 {
8359     HWND hwnd;
8360     MSG msg;
8361     HANDLE hevent = *(HANDLE *)param;
8362
8363     flush_sequence();
8364     /* these events should be received only by our new hook proc,
8365      * an old one does not expect an event from another thread.
8366      */
8367
8368     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8369     assert(hwnd);
8370     trace("created thread window %p\n", hwnd);
8371
8372     *(HWND *)param = hwnd;
8373
8374     /* Windows doesn't like when a thread plays games with the focus,
8375        that leads to all kinds of misbehaviours and failures to activate
8376        a window. So, better keep next lines commented out.
8377     SetFocus(0);
8378     SetFocus(hwnd);*/
8379
8380     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8381     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8382
8383     SetEvent(hevent);
8384
8385     while (GetMessage(&msg, 0, 0, 0))
8386     {
8387         TranslateMessage(&msg);
8388         DispatchMessage(&msg);
8389     }
8390     return 0;
8391 }
8392
8393 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8394 {
8395     HWND hwnd;
8396     MSG msg;
8397     HANDLE hevent = *(HANDLE *)param;
8398
8399     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8400     assert(hwnd);
8401     trace("created thread window %p\n", hwnd);
8402
8403     *(HWND *)param = hwnd;
8404
8405     flush_sequence();
8406
8407     /* Windows doesn't like when a thread plays games with the focus,
8408      * that leads to all kinds of misbehaviours and failures to activate
8409      * a window. So, better don't generate a mouse click message below.
8410      */
8411     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8412     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8413     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8414
8415     SetEvent(hevent);
8416     while (GetMessage(&msg, 0, 0, 0))
8417     {
8418         TranslateMessage(&msg);
8419         DispatchMessage(&msg);
8420     }
8421     return 0;
8422 }
8423
8424 static void test_winevents(void)
8425 {
8426     BOOL ret;
8427     MSG msg;
8428     HWND hwnd, hwnd2;
8429     UINT i;
8430     HANDLE hthread, hevent;
8431     DWORD tid;
8432     HWINEVENTHOOK hhook;
8433     const struct message *events = WmWinEventsSeq;
8434
8435     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8436                            WS_OVERLAPPEDWINDOW,
8437                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8438                            NULL, NULL, 0);
8439     assert(hwnd);
8440
8441     /****** start of global hook test *************/
8442     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8443     if (!hCBT_global_hook)
8444     {
8445         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8446         skip( "cannot set global hook\n" );
8447         return;
8448     }
8449
8450     hevent = CreateEventA(NULL, 0, 0, NULL);
8451     assert(hevent);
8452     hwnd2 = hevent;
8453
8454     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8455     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8456
8457     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8458
8459     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8460
8461     flush_sequence();
8462     /* this one should be received only by old hook proc */
8463     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8464     /* this one should be received only by old hook proc */
8465     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8466
8467     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8468
8469     ret = UnhookWindowsHookEx(hCBT_global_hook);
8470     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8471
8472     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8473     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8474     CloseHandle(hthread);
8475     CloseHandle(hevent);
8476     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8477     /****** end of global hook test *************/
8478
8479     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8480     {
8481         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8482         return;
8483     }
8484
8485     flush_sequence();
8486
8487     if (0)
8488     {
8489     /* this test doesn't pass under Win9x */
8490     /* win2k ignores events with hwnd == 0 */
8491     SetLastError(0xdeadbeef);
8492     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8493     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8494        GetLastError() == 0xdeadbeef, /* Win9x */
8495        "unexpected error %d\n", GetLastError());
8496     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8497     }
8498
8499     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8500         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8501
8502     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8503
8504     /****** start of event filtering test *************/
8505     hhook = pSetWinEventHook(
8506         EVENT_OBJECT_SHOW, /* 0x8002 */
8507         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8508         GetModuleHandleA(0), win_event_global_hook_proc,
8509         GetCurrentProcessId(), 0,
8510         WINEVENT_INCONTEXT);
8511     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8512
8513     hevent = CreateEventA(NULL, 0, 0, NULL);
8514     assert(hevent);
8515     hwnd2 = hevent;
8516
8517     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8518     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8519
8520     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8521
8522     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8523
8524     flush_sequence();
8525     /* this one should be received only by old hook proc */
8526     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8527     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8528     /* this one should be received only by old hook proc */
8529     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8530
8531     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8532
8533     ret = pUnhookWinEvent(hhook);
8534     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8535
8536     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8537     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8538     CloseHandle(hthread);
8539     CloseHandle(hevent);
8540     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8541     /****** end of event filtering test *************/
8542
8543     /****** start of out of context event test *************/
8544     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8545         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8546         WINEVENT_OUTOFCONTEXT);
8547     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8548
8549     hevent = CreateEventA(NULL, 0, 0, NULL);
8550     assert(hevent);
8551     hwnd2 = hevent;
8552
8553     flush_sequence();
8554
8555     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8556     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8557
8558     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8559
8560     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8561     /* process pending winevent messages */
8562     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8563     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8564
8565     flush_sequence();
8566     /* this one should be received only by old hook proc */
8567     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8568     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8569     /* this one should be received only by old hook proc */
8570     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8571
8572     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8573     /* process pending winevent messages */
8574     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8575     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8576
8577     ret = pUnhookWinEvent(hhook);
8578     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8579
8580     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8581     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8582     CloseHandle(hthread);
8583     CloseHandle(hevent);
8584     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8585     /****** end of out of context event test *************/
8586
8587     /****** start of MOUSE_LL hook test *************/
8588     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8589     /* WH_MOUSE_LL is not supported on Win9x platforms */
8590     if (!hCBT_global_hook)
8591     {
8592         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8593         goto skip_mouse_ll_hook_test;
8594     }
8595
8596     hevent = CreateEventA(NULL, 0, 0, NULL);
8597     assert(hevent);
8598     hwnd2 = hevent;
8599
8600     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8601     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8602
8603     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8604         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8605
8606     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8607     flush_sequence();
8608
8609     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8610     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8611     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8612
8613     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8614
8615     ret = UnhookWindowsHookEx(hCBT_global_hook);
8616     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8617
8618     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8619     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8620     CloseHandle(hthread);
8621     CloseHandle(hevent);
8622     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8623     /****** end of MOUSE_LL hook test *************/
8624 skip_mouse_ll_hook_test:
8625
8626     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8627 }
8628
8629 static void test_set_hook(void)
8630 {
8631     BOOL ret;
8632     HHOOK hhook;
8633     HWINEVENTHOOK hwinevent_hook;
8634
8635     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8636     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8637     UnhookWindowsHookEx(hhook);
8638
8639     if (0)
8640     {
8641     /* this test doesn't pass under Win9x: BUG! */
8642     SetLastError(0xdeadbeef);
8643     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8644     ok(!hhook, "global hook requires hModule != 0\n");
8645     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8646     }
8647
8648     SetLastError(0xdeadbeef);
8649     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8650     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8651     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8652        GetLastError() == 0xdeadbeef, /* Win9x */
8653        "unexpected error %d\n", GetLastError());
8654
8655     SetLastError(0xdeadbeef);
8656     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8657     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8658        GetLastError() == 0xdeadbeef, /* Win9x */
8659        "unexpected error %d\n", GetLastError());
8660
8661     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8662
8663     /* even process local incontext hooks require hmodule */
8664     SetLastError(0xdeadbeef);
8665     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8666         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8667     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8668     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8669        GetLastError() == 0xdeadbeef, /* Win9x */
8670        "unexpected error %d\n", GetLastError());
8671
8672     /* even thread local incontext hooks require hmodule */
8673     SetLastError(0xdeadbeef);
8674     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8675         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8676     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8677     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8678        GetLastError() == 0xdeadbeef, /* Win9x */
8679        "unexpected error %d\n", GetLastError());
8680
8681     if (0)
8682     {
8683     /* these 3 tests don't pass under Win9x */
8684     SetLastError(0xdeadbeef);
8685     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8686         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8687     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8688     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8689
8690     SetLastError(0xdeadbeef);
8691     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8692         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8693     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8694     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8695
8696     SetLastError(0xdeadbeef);
8697     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8698         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8699     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8700     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8701     }
8702
8703     SetLastError(0xdeadbeef);
8704     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8705         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8706     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8707     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8708     ret = pUnhookWinEvent(hwinevent_hook);
8709     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8710
8711 todo_wine {
8712     /* This call succeeds under win2k SP4, but fails under Wine.
8713        Does win2k test/use passed process id? */
8714     SetLastError(0xdeadbeef);
8715     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8716         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8717     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8718     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8719     ret = pUnhookWinEvent(hwinevent_hook);
8720     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8721 }
8722
8723     SetLastError(0xdeadbeef);
8724     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8725     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8726         GetLastError() == 0xdeadbeef, /* Win9x */
8727         "unexpected error %d\n", GetLastError());
8728 }
8729
8730 static const struct message ScrollWindowPaint1[] = {
8731     { WM_PAINT, sent },
8732     { WM_ERASEBKGND, sent|beginpaint },
8733     { WM_GETTEXTLENGTH, sent|optional },
8734     { WM_PAINT, sent|optional },
8735     { WM_NCPAINT, sent|beginpaint|optional },
8736     { WM_GETTEXT, sent|beginpaint|optional },
8737     { WM_GETTEXT, sent|beginpaint|optional },
8738     { WM_GETTEXT, sent|beginpaint|optional },
8739     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8740     { WM_ERASEBKGND, sent|beginpaint|optional },
8741     { 0 }
8742 };
8743
8744 static const struct message ScrollWindowPaint2[] = {
8745     { WM_PAINT, sent },
8746     { 0 }
8747 };
8748
8749 static void test_scrollwindowex(void)
8750 {
8751     HWND hwnd, hchild;
8752     RECT rect={0,0,130,130};
8753
8754     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8755             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8756             100, 100, 200, 200, 0, 0, 0, NULL);
8757     ok (hwnd != 0, "Failed to create overlapped window\n");
8758     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8759             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8760             10, 10, 150, 150, hwnd, 0, 0, NULL);
8761     ok (hchild != 0, "Failed to create child\n");
8762     UpdateWindow(hwnd);
8763     flush_events();
8764     flush_sequence();
8765
8766     /* scroll without the child window */
8767     trace("start scroll\n");
8768     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8769             SW_ERASE|SW_INVALIDATE);
8770     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8771     trace("end scroll\n");
8772     flush_sequence();
8773     flush_events();
8774     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8775     flush_events();
8776     flush_sequence();
8777
8778     /* Now without the SW_ERASE flag */
8779     trace("start scroll\n");
8780     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8781     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8782     trace("end scroll\n");
8783     flush_sequence();
8784     flush_events();
8785     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8786     flush_events();
8787     flush_sequence();
8788
8789     /* now scroll the child window as well */
8790     trace("start scroll\n");
8791     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8792             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8793     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8794     /* windows sometimes a WM_MOVE */
8795     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8796     trace("end scroll\n");
8797     flush_sequence();
8798     flush_events();
8799     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8800     flush_events();
8801     flush_sequence();
8802
8803     /* now scroll with ScrollWindow() */
8804     trace("start scroll with ScrollWindow\n");
8805     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8806     trace("end scroll\n");
8807     flush_sequence();
8808     flush_events();
8809     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8810
8811     ok(DestroyWindow(hchild), "failed to destroy window\n");
8812     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8813     flush_sequence();
8814 }
8815
8816 static const struct message destroy_window_with_children[] = {
8817     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8818     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8819     { 0x0090, sent|optional },
8820     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8821     { 0x0090, sent|optional },
8822     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8823     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8824     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8825     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8826     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8827     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8828     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8829     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8830     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8831     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8832     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8833     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8834     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8835     { 0 }
8836 };
8837
8838 static void test_DestroyWindow(void)
8839 {
8840     BOOL ret;
8841     HWND parent, child1, child2, child3, child4, test;
8842     UINT_PTR child_id = WND_CHILD_ID + 1;
8843
8844     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8845                              100, 100, 200, 200, 0, 0, 0, NULL);
8846     assert(parent != 0);
8847     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8848                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8849     assert(child1 != 0);
8850     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8851                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8852     assert(child2 != 0);
8853     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8854                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8855     assert(child3 != 0);
8856     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8857                              0, 0, 50, 50, parent, 0, 0, NULL);
8858     assert(child4 != 0);
8859
8860     /* test owner/parent of child2 */
8861     test = GetParent(child2);
8862     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8863     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8864     if(pGetAncestor) {
8865         test = pGetAncestor(child2, GA_PARENT);
8866         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8867     }
8868     test = GetWindow(child2, GW_OWNER);
8869     ok(!test, "wrong owner %p\n", test);
8870
8871     test = SetParent(child2, parent);
8872     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8873
8874     /* test owner/parent of the parent */
8875     test = GetParent(parent);
8876     ok(!test, "wrong parent %p\n", test);
8877     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8878     if(pGetAncestor) {
8879         test = pGetAncestor(parent, GA_PARENT);
8880         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8881     }
8882     test = GetWindow(parent, GW_OWNER);
8883     ok(!test, "wrong owner %p\n", test);
8884
8885     /* test owner/parent of child1 */
8886     test = GetParent(child1);
8887     ok(test == parent, "wrong parent %p\n", test);
8888     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8889     if(pGetAncestor) {
8890         test = pGetAncestor(child1, GA_PARENT);
8891         ok(test == parent, "wrong parent %p\n", test);
8892     }
8893     test = GetWindow(child1, GW_OWNER);
8894     ok(!test, "wrong owner %p\n", test);
8895
8896     /* test owner/parent of child2 */
8897     test = GetParent(child2);
8898     ok(test == parent, "wrong parent %p\n", test);
8899     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8900     if(pGetAncestor) {
8901         test = pGetAncestor(child2, GA_PARENT);
8902         ok(test == parent, "wrong parent %p\n", test);
8903     }
8904     test = GetWindow(child2, GW_OWNER);
8905     ok(!test, "wrong owner %p\n", test);
8906
8907     /* test owner/parent of child3 */
8908     test = GetParent(child3);
8909     ok(test == child1, "wrong parent %p\n", test);
8910     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8911     if(pGetAncestor) {
8912         test = pGetAncestor(child3, GA_PARENT);
8913         ok(test == child1, "wrong parent %p\n", test);
8914     }
8915     test = GetWindow(child3, GW_OWNER);
8916     ok(!test, "wrong owner %p\n", test);
8917
8918     /* test owner/parent of child4 */
8919     test = GetParent(child4);
8920     ok(test == parent, "wrong parent %p\n", test);
8921     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8922     if(pGetAncestor) {
8923         test = pGetAncestor(child4, GA_PARENT);
8924         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8925     }
8926     test = GetWindow(child4, GW_OWNER);
8927     ok(test == parent, "wrong owner %p\n", test);
8928
8929     flush_sequence();
8930
8931     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8932            parent, child1, child2, child3, child4);
8933
8934     SetCapture(child4);
8935     test = GetCapture();
8936     ok(test == child4, "wrong capture window %p\n", test);
8937
8938     test_DestroyWindow_flag = TRUE;
8939     ret = DestroyWindow(parent);
8940     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8941     test_DestroyWindow_flag = FALSE;
8942     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8943
8944     ok(!IsWindow(parent), "parent still exists\n");
8945     ok(!IsWindow(child1), "child1 still exists\n");
8946     ok(!IsWindow(child2), "child2 still exists\n");
8947     ok(!IsWindow(child3), "child3 still exists\n");
8948     ok(!IsWindow(child4), "child4 still exists\n");
8949
8950     test = GetCapture();
8951     ok(!test, "wrong capture window %p\n", test);
8952 }
8953
8954
8955 static const struct message WmDispatchPaint[] = {
8956     { WM_NCPAINT, sent },
8957     { WM_GETTEXT, sent|defwinproc|optional },
8958     { WM_GETTEXT, sent|defwinproc|optional },
8959     { WM_ERASEBKGND, sent },
8960     { 0 }
8961 };
8962
8963 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8964 {
8965     if (message == WM_PAINT) return 0;
8966     return MsgCheckProcA( hwnd, message, wParam, lParam );
8967 }
8968
8969 static void test_DispatchMessage(void)
8970 {
8971     RECT rect;
8972     MSG msg;
8973     int count;
8974     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8975                                100, 100, 200, 200, 0, 0, 0, NULL);
8976     ShowWindow( hwnd, SW_SHOW );
8977     UpdateWindow( hwnd );
8978     flush_events();
8979     flush_sequence();
8980     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8981
8982     SetRect( &rect, -5, -5, 5, 5 );
8983     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8984     count = 0;
8985     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8986     {
8987         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8988         else
8989         {
8990             flush_sequence();
8991             DispatchMessage( &msg );
8992             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8993             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8994             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8995             if (++count > 10) break;
8996         }
8997     }
8998     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8999
9000     trace("now without DispatchMessage\n");
9001     flush_sequence();
9002     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9003     count = 0;
9004     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9005     {
9006         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9007         else
9008         {
9009             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9010             flush_sequence();
9011             /* this will send WM_NCCPAINT just like DispatchMessage does */
9012             GetUpdateRgn( hwnd, hrgn, TRUE );
9013             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9014             DeleteObject( hrgn );
9015             GetClientRect( hwnd, &rect );
9016             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
9017             ok( !count, "Got multiple WM_PAINTs\n" );
9018             if (++count > 10) break;
9019         }
9020     }
9021     DestroyWindow(hwnd);
9022 }
9023
9024
9025 static const struct message WmUser[] = {
9026     { WM_USER, sent },
9027     { 0 }
9028 };
9029
9030 struct sendmsg_info
9031 {
9032     HWND  hwnd;
9033     DWORD timeout;
9034     DWORD ret;
9035 };
9036
9037 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9038 {
9039     struct sendmsg_info *info = arg;
9040     SetLastError( 0xdeadbeef );
9041     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9042     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9043                         broken(GetLastError() == 0),  /* win9x */
9044                         "unexpected error %d\n", GetLastError());
9045     return 0;
9046 }
9047
9048 static void wait_for_thread( HANDLE thread )
9049 {
9050     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9051     {
9052         MSG msg;
9053         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
9054     }
9055 }
9056
9057 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9058 {
9059     if (message == WM_USER) Sleep(200);
9060     return MsgCheckProcA( hwnd, message, wParam, lParam );
9061 }
9062
9063 static void test_SendMessageTimeout(void)
9064 {
9065     HANDLE thread;
9066     struct sendmsg_info info;
9067     DWORD tid;
9068     BOOL is_win9x;
9069
9070     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9071                                100, 100, 200, 200, 0, 0, 0, NULL);
9072     flush_events();
9073     flush_sequence();
9074
9075     info.timeout = 1000;
9076     info.ret = 0xdeadbeef;
9077     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9078     wait_for_thread( thread );
9079     CloseHandle( thread );
9080     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9081     ok_sequence( WmUser, "WmUser", FALSE );
9082
9083     info.timeout = 1;
9084     info.ret = 0xdeadbeef;
9085     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9086     Sleep(100);  /* SendMessageTimeout should time out here */
9087     wait_for_thread( thread );
9088     CloseHandle( thread );
9089     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9090     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9091
9092     /* 0 means infinite timeout (but not on win9x) */
9093     info.timeout = 0;
9094     info.ret = 0xdeadbeef;
9095     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9096     Sleep(100);
9097     wait_for_thread( thread );
9098     CloseHandle( thread );
9099     is_win9x = !info.ret;
9100     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9101     else ok_sequence( WmUser, "WmUser", FALSE );
9102
9103     /* timeout is treated as signed despite the prototype (but not on win9x) */
9104     info.timeout = 0x7fffffff;
9105     info.ret = 0xdeadbeef;
9106     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9107     Sleep(100);
9108     wait_for_thread( thread );
9109     CloseHandle( thread );
9110     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9111     ok_sequence( WmUser, "WmUser", FALSE );
9112
9113     info.timeout = 0x80000000;
9114     info.ret = 0xdeadbeef;
9115     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9116     Sleep(100);
9117     wait_for_thread( thread );
9118     CloseHandle( thread );
9119     if (is_win9x)
9120     {
9121         ok( info.ret == 1, "SendMessageTimeout failed\n" );
9122         ok_sequence( WmUser, "WmUser", FALSE );
9123     }
9124     else
9125     {
9126         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9127         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9128     }
9129
9130     /* now check for timeout during message processing */
9131     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9132     info.timeout = 100;
9133     info.ret = 0xdeadbeef;
9134     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9135     wait_for_thread( thread );
9136     CloseHandle( thread );
9137     /* we should time out but still get the message */
9138     ok( info.ret == 0, "SendMessageTimeout failed\n" );
9139     ok_sequence( WmUser, "WmUser", FALSE );
9140
9141     DestroyWindow( info.hwnd );
9142 }
9143
9144
9145 /****************** edit message test *************************/
9146 #define ID_EDIT 0x1234
9147 static const struct message sl_edit_setfocus[] =
9148 {
9149     { HCBT_SETFOCUS, hook },
9150     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9151     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9152     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9153     { WM_SETFOCUS, sent|wparam, 0 },
9154     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9155     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9156     { WM_CTLCOLOREDIT, sent|parent },
9157     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9158     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9159     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9160     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9161     { 0 }
9162 };
9163 static const struct message ml_edit_setfocus[] =
9164 {
9165     { HCBT_SETFOCUS, hook },
9166     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9167     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9168     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9169     { WM_SETFOCUS, sent|wparam, 0 },
9170     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9171     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9172     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9173     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9174     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9175     { 0 }
9176 };
9177 static const struct message sl_edit_killfocus[] =
9178 {
9179     { HCBT_SETFOCUS, hook },
9180     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9181     { WM_KILLFOCUS, sent|wparam, 0 },
9182     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9183     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9184     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9185     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9186     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9187     { 0 }
9188 };
9189 static const struct message sl_edit_lbutton_dblclk[] =
9190 {
9191     { WM_LBUTTONDBLCLK, sent },
9192     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9193     { 0 }
9194 };
9195 static const struct message sl_edit_lbutton_down[] =
9196 {
9197     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9198     { HCBT_SETFOCUS, hook },
9199     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9200     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9201     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9202     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9203     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9204     { WM_CTLCOLOREDIT, sent|parent },
9205     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9206     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9207     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9208     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9209     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9210     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9211     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9212     { WM_CTLCOLOREDIT, sent|parent|optional },
9213     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9214     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9215     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9216     { 0 }
9217 };
9218 static const struct message ml_edit_lbutton_down[] =
9219 {
9220     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9221     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9222     { HCBT_SETFOCUS, hook },
9223     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9224     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9225     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9226     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9227     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9228     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9229     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9230     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9231     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9232     { 0 }
9233 };
9234 static const struct message sl_edit_lbutton_up[] =
9235 {
9236     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9237     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9238     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9239     { WM_CAPTURECHANGED, sent|defwinproc },
9240     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9241     { 0 }
9242 };
9243 static const struct message ml_edit_lbutton_up[] =
9244 {
9245     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9246     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9247     { WM_CAPTURECHANGED, sent|defwinproc },
9248     { 0 }
9249 };
9250
9251 static WNDPROC old_edit_proc;
9252
9253 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9254 {
9255     static LONG defwndproc_counter = 0;
9256     LRESULT ret;
9257     struct recvd_message msg;
9258
9259     if (ignore_message( message )) return 0;
9260
9261     msg.hwnd = hwnd;
9262     msg.message = message;
9263     msg.flags = sent|wparam|lparam;
9264     if (defwndproc_counter) msg.flags |= defwinproc;
9265     msg.wParam = wParam;
9266     msg.lParam = lParam;
9267     msg.descr = "edit";
9268     add_message(&msg);
9269
9270     defwndproc_counter++;
9271     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9272     defwndproc_counter--;
9273
9274     return ret;
9275 }
9276
9277 static void subclass_edit(void)
9278 {
9279     WNDCLASSA cls;
9280
9281     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9282
9283     old_edit_proc = cls.lpfnWndProc;
9284
9285     cls.hInstance = GetModuleHandle(0);
9286     cls.lpfnWndProc = edit_hook_proc;
9287     cls.lpszClassName = "my_edit_class";
9288     UnregisterClass(cls.lpszClassName, cls.hInstance);
9289     if (!RegisterClassA(&cls)) assert(0);
9290 }
9291
9292 static void test_edit_messages(void)
9293 {
9294     HWND hwnd, parent;
9295     DWORD dlg_code;
9296
9297     subclass_edit();
9298     log_all_parent_messages++;
9299
9300     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9301                              100, 100, 200, 200, 0, 0, 0, NULL);
9302     ok (parent != 0, "Failed to create parent window\n");
9303
9304     /* test single line edit */
9305     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9306                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9307     ok(hwnd != 0, "Failed to create edit window\n");
9308
9309     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9310     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9311
9312     ShowWindow(hwnd, SW_SHOW);
9313     UpdateWindow(hwnd);
9314     SetFocus(0);
9315     flush_sequence();
9316
9317     SetFocus(hwnd);
9318     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9319
9320     SetFocus(0);
9321     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9322
9323     SetFocus(0);
9324     ReleaseCapture();
9325     flush_sequence();
9326
9327     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9328     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9329
9330     SetFocus(0);
9331     ReleaseCapture();
9332     flush_sequence();
9333
9334     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9335     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9336
9337     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9338     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9339
9340     DestroyWindow(hwnd);
9341
9342     /* test multiline edit */
9343     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9344                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9345     ok(hwnd != 0, "Failed to create edit window\n");
9346
9347     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9348     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9349        "wrong dlg_code %08x\n", dlg_code);
9350
9351     ShowWindow(hwnd, SW_SHOW);
9352     UpdateWindow(hwnd);
9353     SetFocus(0);
9354     flush_sequence();
9355
9356     SetFocus(hwnd);
9357     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9358
9359     SetFocus(0);
9360     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9361
9362     SetFocus(0);
9363     ReleaseCapture();
9364     flush_sequence();
9365
9366     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9367     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9368
9369     SetFocus(0);
9370     ReleaseCapture();
9371     flush_sequence();
9372
9373     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9374     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9375
9376     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9377     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9378
9379     DestroyWindow(hwnd);
9380     DestroyWindow(parent);
9381
9382     log_all_parent_messages--;
9383 }
9384
9385 /**************************** End of Edit test ******************************/
9386
9387 static const struct message WmKeyDownSkippedSeq[] =
9388 {
9389     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9390     { 0 }
9391 };
9392 static const struct message WmKeyDownWasDownSkippedSeq[] =
9393 {
9394     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9395     { 0 }
9396 };
9397 static const struct message WmKeyUpSkippedSeq[] =
9398 {
9399     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9400     { 0 }
9401 };
9402 static const struct message WmUserKeyUpSkippedSeq[] =
9403 {
9404     { WM_USER, sent },
9405     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9406     { 0 }
9407 };
9408
9409 #define EV_STOP 0
9410 #define EV_SENDMSG 1
9411 #define EV_ACK 2
9412
9413 struct peekmsg_info
9414 {
9415     HWND  hwnd;
9416     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9417 };
9418
9419 static DWORD CALLBACK send_msg_thread_2(void *param)
9420 {
9421     DWORD ret;
9422     struct peekmsg_info *info = param;
9423
9424     trace("thread: looping\n");
9425     SetEvent(info->hevent[EV_ACK]);
9426
9427     while (1)
9428     {
9429         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9430
9431         switch (ret)
9432         {
9433         case WAIT_OBJECT_0 + EV_STOP:
9434             trace("thread: exiting\n");
9435             return 0;
9436
9437         case WAIT_OBJECT_0 + EV_SENDMSG:
9438             trace("thread: sending message\n");
9439             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
9440                 "SendNotifyMessageA failed error %u\n", GetLastError());
9441             SetEvent(info->hevent[EV_ACK]);
9442             break;
9443
9444         default:
9445             trace("unexpected return: %04x\n", ret);
9446             assert(0);
9447             break;
9448         }
9449     }
9450     return 0;
9451 }
9452
9453 static void test_PeekMessage(void)
9454 {
9455     MSG msg;
9456     HANDLE hthread;
9457     DWORD tid, qstatus;
9458     UINT qs_all_input = QS_ALLINPUT;
9459     UINT qs_input = QS_INPUT;
9460     BOOL ret;
9461     struct peekmsg_info info;
9462
9463     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9464                               100, 100, 200, 200, 0, 0, 0, NULL);
9465     assert(info.hwnd);
9466     ShowWindow(info.hwnd, SW_SHOW);
9467     UpdateWindow(info.hwnd);
9468     SetFocus(info.hwnd);
9469
9470     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9471     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9472     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9473
9474     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9475     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9476
9477     flush_events();
9478     flush_sequence();
9479
9480     SetLastError(0xdeadbeef);
9481     qstatus = GetQueueStatus(qs_all_input);
9482     if (GetLastError() == ERROR_INVALID_FLAGS)
9483     {
9484         trace("QS_RAWINPUT not supported on this platform\n");
9485         qs_all_input &= ~QS_RAWINPUT;
9486         qs_input &= ~QS_RAWINPUT;
9487     }
9488     if (qstatus & QS_POSTMESSAGE)
9489     {
9490         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9491         qstatus = GetQueueStatus(qs_all_input);
9492     }
9493     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9494
9495     trace("signalling to send message\n");
9496     SetEvent(info.hevent[EV_SENDMSG]);
9497     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9498
9499     /* pass invalid QS_xxxx flags */
9500     SetLastError(0xdeadbeef);
9501     qstatus = GetQueueStatus(0xffffffff);
9502     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9503     if (!qstatus)
9504     {
9505         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9506         qstatus = GetQueueStatus(qs_all_input);
9507     }
9508     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9509     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9510        "wrong qstatus %08x\n", qstatus);
9511
9512     msg.message = 0;
9513     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9514     ok(!ret,
9515        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9516         msg.message);
9517     ok_sequence(WmUser, "WmUser", FALSE);
9518
9519     qstatus = GetQueueStatus(qs_all_input);
9520     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9521
9522     keybd_event('N', 0, 0, 0);
9523     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9524     qstatus = GetQueueStatus(qs_all_input);
9525     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9526     {
9527         skip( "queuing key events not supported\n" );
9528         goto done;
9529     }
9530     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9531        /* keybd_event seems to trigger a sent message on NT4 */
9532        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9533        "wrong qstatus %08x\n", qstatus);
9534
9535     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9536     qstatus = GetQueueStatus(qs_all_input);
9537     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9538        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9539        "wrong qstatus %08x\n", qstatus);
9540
9541     InvalidateRect(info.hwnd, NULL, FALSE);
9542     qstatus = GetQueueStatus(qs_all_input);
9543     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9544        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9545        "wrong qstatus %08x\n", qstatus);
9546
9547     trace("signalling to send message\n");
9548     SetEvent(info.hevent[EV_SENDMSG]);
9549     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9550
9551     qstatus = GetQueueStatus(qs_all_input);
9552     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9553        "wrong qstatus %08x\n", qstatus);
9554
9555     msg.message = 0;
9556     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9557     if (ret && msg.message == WM_CHAR)
9558     {
9559         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9560         goto done;
9561     }
9562     ok(!ret,
9563        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9564         msg.message);
9565     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9566     {
9567         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9568         goto done;
9569     }
9570     ok_sequence(WmUser, "WmUser", FALSE);
9571
9572     qstatus = GetQueueStatus(qs_all_input);
9573     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9574        "wrong qstatus %08x\n", qstatus);
9575
9576     trace("signalling to send message\n");
9577     SetEvent(info.hevent[EV_SENDMSG]);
9578     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9579
9580     qstatus = GetQueueStatus(qs_all_input);
9581     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9582        "wrong qstatus %08x\n", qstatus);
9583
9584     msg.message = 0;
9585     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9586     ok(!ret,
9587        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9588         msg.message);
9589     ok_sequence(WmUser, "WmUser", FALSE);
9590
9591     qstatus = GetQueueStatus(qs_all_input);
9592     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9593        "wrong qstatus %08x\n", qstatus);
9594
9595     msg.message = 0;
9596     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9597     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9598        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9599        ret, msg.message, msg.wParam);
9600     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9601
9602     qstatus = GetQueueStatus(qs_all_input);
9603     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9604        "wrong qstatus %08x\n", qstatus);
9605
9606     msg.message = 0;
9607     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9608     ok(!ret,
9609        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9610         msg.message);
9611     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9612
9613     qstatus = GetQueueStatus(qs_all_input);
9614     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9615        "wrong qstatus %08x\n", qstatus);
9616
9617     msg.message = 0;
9618     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9619     ok(ret && msg.message == WM_PAINT,
9620        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9621     DispatchMessageA(&msg);
9622     ok_sequence(WmPaint, "WmPaint", FALSE);
9623
9624     qstatus = GetQueueStatus(qs_all_input);
9625     ok(qstatus == MAKELONG(0, QS_KEY),
9626        "wrong qstatus %08x\n", qstatus);
9627
9628     msg.message = 0;
9629     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9630     ok(!ret,
9631        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9632         msg.message);
9633     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9634
9635     qstatus = GetQueueStatus(qs_all_input);
9636     ok(qstatus == MAKELONG(0, QS_KEY),
9637        "wrong qstatus %08x\n", qstatus);
9638
9639     trace("signalling to send message\n");
9640     SetEvent(info.hevent[EV_SENDMSG]);
9641     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9642
9643     qstatus = GetQueueStatus(qs_all_input);
9644     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9645        "wrong qstatus %08x\n", qstatus);
9646
9647     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9648
9649     qstatus = GetQueueStatus(qs_all_input);
9650     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9651        "wrong qstatus %08x\n", qstatus);
9652
9653     msg.message = 0;
9654     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9655     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9656        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9657        ret, msg.message, msg.wParam);
9658     ok_sequence(WmUser, "WmUser", FALSE);
9659
9660     qstatus = GetQueueStatus(qs_all_input);
9661     ok(qstatus == MAKELONG(0, QS_KEY),
9662        "wrong qstatus %08x\n", qstatus);
9663
9664     msg.message = 0;
9665     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9666     ok(!ret,
9667        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9668         msg.message);
9669     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9670
9671     qstatus = GetQueueStatus(qs_all_input);
9672     ok(qstatus == MAKELONG(0, QS_KEY),
9673        "wrong qstatus %08x\n", qstatus);
9674
9675     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9676
9677     qstatus = GetQueueStatus(qs_all_input);
9678     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9679        "wrong qstatus %08x\n", qstatus);
9680
9681     trace("signalling to send message\n");
9682     SetEvent(info.hevent[EV_SENDMSG]);
9683     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9684
9685     qstatus = GetQueueStatus(qs_all_input);
9686     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9687        "wrong qstatus %08x\n", qstatus);
9688
9689     msg.message = 0;
9690     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9691     ok(!ret,
9692        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9693         msg.message);
9694     ok_sequence(WmUser, "WmUser", FALSE);
9695
9696     qstatus = GetQueueStatus(qs_all_input);
9697     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9698        "wrong qstatus %08x\n", qstatus);
9699
9700     msg.message = 0;
9701     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9702         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9703     else /* workaround for a missing QS_RAWINPUT support */
9704         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9705     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9706        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9707        ret, msg.message, msg.wParam);
9708     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9709
9710     qstatus = GetQueueStatus(qs_all_input);
9711     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9712        "wrong qstatus %08x\n", qstatus);
9713
9714     msg.message = 0;
9715     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9716         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9717     else /* workaround for a missing QS_RAWINPUT support */
9718         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9719     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9720        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9721        ret, msg.message, msg.wParam);
9722     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9723
9724     qstatus = GetQueueStatus(qs_all_input);
9725     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9726        "wrong qstatus %08x\n", qstatus);
9727
9728     msg.message = 0;
9729     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9730     ok(!ret,
9731        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9732         msg.message);
9733     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9734
9735     qstatus = GetQueueStatus(qs_all_input);
9736     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9737        "wrong qstatus %08x\n", qstatus);
9738
9739     msg.message = 0;
9740     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9741     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9742        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9743        ret, msg.message, msg.wParam);
9744     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9745
9746     qstatus = GetQueueStatus(qs_all_input);
9747     ok(qstatus == 0,
9748        "wrong qstatus %08x\n", qstatus);
9749
9750     msg.message = 0;
9751     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9752     ok(!ret,
9753        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9754         msg.message);
9755     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9756
9757     qstatus = GetQueueStatus(qs_all_input);
9758     ok(qstatus == 0,
9759        "wrong qstatus %08x\n", qstatus);
9760
9761     /* test whether presence of the quit flag in the queue affects
9762      * the queue state
9763      */
9764     PostQuitMessage(0x1234abcd);
9765
9766     qstatus = GetQueueStatus(qs_all_input);
9767     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9768        "wrong qstatus %08x\n", qstatus);
9769
9770     PostMessageA(info.hwnd, WM_USER, 0, 0);
9771
9772     qstatus = GetQueueStatus(qs_all_input);
9773     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9774        "wrong qstatus %08x\n", qstatus);
9775
9776     msg.message = 0;
9777     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9778     ok(ret && msg.message == WM_USER,
9779        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9780     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9781
9782     qstatus = GetQueueStatus(qs_all_input);
9783     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9784        "wrong qstatus %08x\n", qstatus);
9785
9786     msg.message = 0;
9787     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9788     ok(ret && msg.message == WM_QUIT,
9789        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9790     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9791     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9792     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9793
9794     qstatus = GetQueueStatus(qs_all_input);
9795 todo_wine {
9796     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9797        "wrong qstatus %08x\n", qstatus);
9798 }
9799
9800     msg.message = 0;
9801     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9802     ok(!ret,
9803        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9804         msg.message);
9805     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9806
9807     qstatus = GetQueueStatus(qs_all_input);
9808     ok(qstatus == 0,
9809        "wrong qstatus %08x\n", qstatus);
9810
9811     /* some GetMessage tests */
9812
9813     keybd_event('N', 0, 0, 0);
9814     qstatus = GetQueueStatus(qs_all_input);
9815     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9816
9817     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9818     qstatus = GetQueueStatus(qs_all_input);
9819     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9820
9821     if (qstatus)
9822     {
9823         ret = GetMessageA( &msg, 0, 0, 0 );
9824         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9825            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9826            ret, msg.message, msg.wParam);
9827         qstatus = GetQueueStatus(qs_all_input);
9828         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9829     }
9830
9831     if (qstatus)
9832     {
9833         ret = GetMessageA( &msg, 0, 0, 0 );
9834         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9835            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9836            ret, msg.message, msg.wParam);
9837         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9838         qstatus = GetQueueStatus(qs_all_input);
9839         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9840     }
9841
9842     keybd_event('N', 0, 0, 0);
9843     qstatus = GetQueueStatus(qs_all_input);
9844     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9845
9846     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9847     qstatus = GetQueueStatus(qs_all_input);
9848     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9849
9850     if (qstatus & (QS_KEY << 16))
9851     {
9852         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9853         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9854            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9855            ret, msg.message, msg.wParam);
9856         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9857         qstatus = GetQueueStatus(qs_all_input);
9858         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9859     }
9860
9861     if (qstatus)
9862     {
9863         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9864         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9865            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9866            ret, msg.message, msg.wParam);
9867         qstatus = GetQueueStatus(qs_all_input);
9868         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9869     }
9870
9871     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9872     qstatus = GetQueueStatus(qs_all_input);
9873     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9874
9875     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9876     qstatus = GetQueueStatus(qs_all_input);
9877     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9878
9879     trace("signalling to send message\n");
9880     SetEvent(info.hevent[EV_SENDMSG]);
9881     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9882     qstatus = GetQueueStatus(qs_all_input);
9883     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9884        "wrong qstatus %08x\n", qstatus);
9885
9886     if (qstatus & (QS_KEY << 16))
9887     {
9888         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9889         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9890            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9891            ret, msg.message, msg.wParam);
9892         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9893         qstatus = GetQueueStatus(qs_all_input);
9894         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9895     }
9896
9897     if (qstatus)
9898     {
9899         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9900         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9901            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9902            ret, msg.message, msg.wParam);
9903         qstatus = GetQueueStatus(qs_all_input);
9904         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9905     }
9906 done:
9907     trace("signalling to exit\n");
9908     SetEvent(info.hevent[EV_STOP]);
9909
9910     WaitForSingleObject(hthread, INFINITE);
9911
9912     CloseHandle(hthread);
9913     CloseHandle(info.hevent[0]);
9914     CloseHandle(info.hevent[1]);
9915     CloseHandle(info.hevent[2]);
9916
9917     DestroyWindow(info.hwnd);
9918 }
9919
9920 static void wait_move_event(HWND hwnd, int x, int y)
9921 {
9922     MSG msg;
9923     DWORD time;
9924     BOOL  ret;
9925     int go = 0;
9926
9927     time = GetTickCount();
9928     while (GetTickCount() - time < 200 && !go) {
9929         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9930         go  = ret && msg.pt.x > x && msg.pt.y > y;
9931         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9932     }
9933 }
9934
9935 #define STEP 5
9936 static void test_PeekMessage2(void)
9937 {
9938     HWND hwnd;
9939     BOOL ret;
9940     MSG msg;
9941     UINT message;
9942     DWORD time1, time2, time3;
9943     int x1, y1, x2, y2, x3, y3;
9944     POINT pos;
9945
9946     time1 = time2 = time3 = 0;
9947     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9948
9949     /* Initialise window and make sure it is ready for events */
9950     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9951                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9952     assert(hwnd);
9953     trace("Window for test_PeekMessage2 %p\n", hwnd);
9954     ShowWindow(hwnd, SW_SHOW);
9955     UpdateWindow(hwnd);
9956     SetFocus(hwnd);
9957     GetCursorPos(&pos);
9958     SetCursorPos(100, 100);
9959     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9960     flush_events();
9961
9962     /* Do initial mousemove, wait until we can see it
9963        and then do our test peek with PM_NOREMOVE. */
9964     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9965     wait_move_event(hwnd, 100-STEP, 100-STEP);
9966
9967     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9968     if (!ret)
9969     {
9970         skip( "queuing mouse events not supported\n" );
9971         goto done;
9972     }
9973     else
9974     {
9975         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9976         message = msg.message;
9977         time1 = msg.time;
9978         x1 = msg.pt.x;
9979         y1 = msg.pt.y;
9980         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9981     }
9982
9983     /* Allow time to advance a bit, and then simulate the user moving their
9984      * mouse around. After that we peek again with PM_NOREMOVE.
9985      * Although the previous mousemove message was never removed, the
9986      * mousemove we now peek should reflect the recent mouse movements
9987      * because the input queue will merge the move events. */
9988     Sleep(100);
9989     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9990     wait_move_event(hwnd, x1, y1);
9991
9992     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9993     ok(ret, "no message available\n");
9994     if (ret) {
9995         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9996         message = msg.message;
9997         time2 = msg.time;
9998         x2 = msg.pt.x;
9999         y2 = msg.pt.y;
10000         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10001         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10002         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10003     }
10004
10005     /* Have another go, to drive the point home */
10006     Sleep(100);
10007     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10008     wait_move_event(hwnd, x2, y2);
10009
10010     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10011     ok(ret, "no message available\n");
10012     if (ret) {
10013         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10014         message = msg.message;
10015         time3 = msg.time;
10016         x3 = msg.pt.x;
10017         y3 = msg.pt.y;
10018         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10019         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10020         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10021     }
10022
10023 done:
10024     DestroyWindow(hwnd);
10025     SetCursorPos(pos.x, pos.y);
10026     flush_events();
10027 }
10028
10029 static void test_quit_message(void)
10030 {
10031     MSG msg;
10032     BOOL ret;
10033
10034     /* test using PostQuitMessage */
10035     flush_events();
10036     PostQuitMessage(0xbeef);
10037
10038     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10039     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10040     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10041     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10042
10043     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10044     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10045
10046     ret = GetMessage(&msg, NULL, 0, 0);
10047     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10048     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10049
10050     /* note: WM_QUIT message received after WM_USER message */
10051     ret = GetMessage(&msg, NULL, 0, 0);
10052     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10053     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10054     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10055
10056     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10057     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10058
10059     /* now test with PostThreadMessage - different behaviour! */
10060     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10061
10062     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10063     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10064     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10065     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10066
10067     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10068     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10069
10070     /* note: we receive the WM_QUIT message first this time */
10071     ret = GetMessage(&msg, NULL, 0, 0);
10072     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10073     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10074     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10075
10076     ret = GetMessage(&msg, NULL, 0, 0);
10077     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10078     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10079 }
10080
10081 static const struct message WmMouseHoverSeq[] = {
10082     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10083     { WM_MOUSEACTIVATE, sent|optional },
10084     { WM_TIMER, sent|optional }, /* XP sends it */
10085     { WM_SYSTIMER, sent },
10086     { WM_MOUSEHOVER, sent|wparam, 0 },
10087     { 0 }
10088 };
10089
10090 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10091 {
10092     MSG msg;
10093     DWORD start_ticks, end_ticks;
10094
10095     start_ticks = GetTickCount();
10096     /* add some deviation (50%) to cover not expected delays */
10097     start_ticks += timeout / 2;
10098
10099     do
10100     {
10101         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10102         {
10103             /* Timer proc messages are not dispatched to the window proc,
10104              * and therefore not logged.
10105              */
10106             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10107             {
10108                 struct recvd_message s_msg;
10109
10110                 s_msg.hwnd = msg.hwnd;
10111                 s_msg.message = msg.message;
10112                 s_msg.flags = sent|wparam|lparam;
10113                 s_msg.wParam = msg.wParam;
10114                 s_msg.lParam = msg.lParam;
10115                 s_msg.descr = "msg_loop";
10116                 add_message(&s_msg);
10117             }
10118             DispatchMessage(&msg);
10119         }
10120
10121         end_ticks = GetTickCount();
10122
10123         /* inject WM_MOUSEMOVE to see how it changes tracking */
10124         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10125         {
10126             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10127             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10128
10129             inject_mouse_move = FALSE;
10130         }
10131     } while (start_ticks + timeout >= end_ticks);
10132 }
10133
10134 static void test_TrackMouseEvent(void)
10135 {
10136     TRACKMOUSEEVENT tme;
10137     BOOL ret;
10138     HWND hwnd, hchild;
10139     RECT rc_parent, rc_child;
10140     UINT default_hover_time, hover_width = 0, hover_height = 0;
10141
10142 #define track_hover(track_hwnd, track_hover_time) \
10143     tme.cbSize = sizeof(tme); \
10144     tme.dwFlags = TME_HOVER; \
10145     tme.hwndTrack = track_hwnd; \
10146     tme.dwHoverTime = track_hover_time; \
10147     SetLastError(0xdeadbeef); \
10148     ret = pTrackMouseEvent(&tme); \
10149     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10150
10151 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10152     tme.cbSize = sizeof(tme); \
10153     tme.dwFlags = TME_QUERY; \
10154     tme.hwndTrack = (HWND)0xdeadbeef; \
10155     tme.dwHoverTime = 0xdeadbeef; \
10156     SetLastError(0xdeadbeef); \
10157     ret = pTrackMouseEvent(&tme); \
10158     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10159     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10160     ok(tme.dwFlags == (expected_track_flags), \
10161        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10162     ok(tme.hwndTrack == (expected_track_hwnd), \
10163        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10164     ok(tme.dwHoverTime == (expected_hover_time), \
10165        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10166
10167 #define track_hover_cancel(track_hwnd) \
10168     tme.cbSize = sizeof(tme); \
10169     tme.dwFlags = TME_HOVER | TME_CANCEL; \
10170     tme.hwndTrack = track_hwnd; \
10171     tme.dwHoverTime = 0xdeadbeef; \
10172     SetLastError(0xdeadbeef); \
10173     ret = pTrackMouseEvent(&tme); \
10174     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10175
10176     default_hover_time = 0xdeadbeef;
10177     SetLastError(0xdeadbeef);
10178     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10179     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10180        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10181     if (!ret) default_hover_time = 400;
10182     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10183
10184     SetLastError(0xdeadbeef);
10185     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10186     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10187        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10188     if (!ret) hover_width = 4;
10189     SetLastError(0xdeadbeef);
10190     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10191     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10192        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10193     if (!ret) hover_height = 4;
10194     trace("hover rect is %u x %d\n", hover_width, hover_height);
10195
10196     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
10197                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10198                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10199                           NULL, NULL, 0);
10200     assert(hwnd);
10201
10202     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
10203                           WS_CHILD | WS_BORDER | WS_VISIBLE,
10204                           50, 50, 200, 200, hwnd,
10205                           NULL, NULL, 0);
10206     assert(hchild);
10207
10208     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10209     flush_events();
10210     flush_sequence();
10211
10212     tme.cbSize = 0;
10213     tme.dwFlags = TME_QUERY;
10214     tme.hwndTrack = (HWND)0xdeadbeef;
10215     tme.dwHoverTime = 0xdeadbeef;
10216     SetLastError(0xdeadbeef);
10217     ret = pTrackMouseEvent(&tme);
10218     ok(!ret, "TrackMouseEvent should fail\n");
10219     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10220        "not expected error %u\n", GetLastError());
10221
10222     tme.cbSize = sizeof(tme);
10223     tme.dwFlags = TME_HOVER;
10224     tme.hwndTrack = (HWND)0xdeadbeef;
10225     tme.dwHoverTime = 0xdeadbeef;
10226     SetLastError(0xdeadbeef);
10227     ret = pTrackMouseEvent(&tme);
10228     ok(!ret, "TrackMouseEvent should fail\n");
10229     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10230        "not expected error %u\n", GetLastError());
10231
10232     tme.cbSize = sizeof(tme);
10233     tme.dwFlags = TME_HOVER | TME_CANCEL;
10234     tme.hwndTrack = (HWND)0xdeadbeef;
10235     tme.dwHoverTime = 0xdeadbeef;
10236     SetLastError(0xdeadbeef);
10237     ret = pTrackMouseEvent(&tme);
10238     ok(!ret, "TrackMouseEvent should fail\n");
10239     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10240        "not expected error %u\n", GetLastError());
10241
10242     GetWindowRect(hwnd, &rc_parent);
10243     GetWindowRect(hchild, &rc_child);
10244     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10245
10246     /* Process messages so that the system updates its internal current
10247      * window and hittest, otherwise TrackMouseEvent calls don't have any
10248      * effect.
10249      */
10250     flush_events();
10251     flush_sequence();
10252
10253     track_query(0, NULL, 0);
10254     track_hover(hchild, 0);
10255     track_query(0, NULL, 0);
10256
10257     flush_events();
10258     flush_sequence();
10259
10260     track_hover(hwnd, 0);
10261     tme.cbSize = sizeof(tme);
10262     tme.dwFlags = TME_QUERY;
10263     tme.hwndTrack = (HWND)0xdeadbeef;
10264     tme.dwHoverTime = 0xdeadbeef;
10265     SetLastError(0xdeadbeef);
10266     ret = pTrackMouseEvent(&tme);
10267     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10268     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10269     if (!tme.dwFlags)
10270     {
10271         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10272         DestroyWindow( hwnd );
10273         return;
10274     }
10275     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10276     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10277     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10278        tme.dwHoverTime, default_hover_time);
10279
10280     pump_msg_loop_timeout(default_hover_time, FALSE);
10281     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10282
10283     track_query(0, NULL, 0);
10284
10285     track_hover(hwnd, HOVER_DEFAULT);
10286     track_query(TME_HOVER, hwnd, default_hover_time);
10287
10288     Sleep(default_hover_time / 2);
10289     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10290     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10291
10292     track_query(TME_HOVER, hwnd, default_hover_time);
10293
10294     pump_msg_loop_timeout(default_hover_time, FALSE);
10295     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10296
10297     track_query(0, NULL, 0);
10298
10299     track_hover(hwnd, HOVER_DEFAULT);
10300     track_query(TME_HOVER, hwnd, default_hover_time);
10301
10302     pump_msg_loop_timeout(default_hover_time, TRUE);
10303     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10304
10305     track_query(0, NULL, 0);
10306
10307     track_hover(hwnd, HOVER_DEFAULT);
10308     track_query(TME_HOVER, hwnd, default_hover_time);
10309     track_hover_cancel(hwnd);
10310
10311     DestroyWindow(hwnd);
10312
10313 #undef track_hover
10314 #undef track_query
10315 #undef track_hover_cancel
10316 }
10317
10318
10319 static const struct message WmSetWindowRgn[] = {
10320     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10321     { WM_NCCALCSIZE, sent|wparam, 1 },
10322     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10323     { WM_GETTEXT, sent|defwinproc|optional },
10324     { WM_ERASEBKGND, sent|optional },
10325     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10326     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10327     { 0 }
10328 };
10329
10330 static const struct message WmSetWindowRgn_no_redraw[] = {
10331     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10332     { WM_NCCALCSIZE, sent|wparam, 1 },
10333     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10334     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10335     { 0 }
10336 };
10337
10338 static const struct message WmSetWindowRgn_clear[] = {
10339     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10340     { WM_NCCALCSIZE, sent|wparam, 1 },
10341     { WM_NCPAINT, sent|optional },
10342     { WM_GETTEXT, sent|defwinproc|optional },
10343     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10344     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10345     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10346     { WM_NCPAINT, sent|optional },
10347     { WM_GETTEXT, sent|defwinproc|optional },
10348     { WM_ERASEBKGND, sent|optional },
10349     { WM_WINDOWPOSCHANGING, sent|optional },
10350     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10351     { WM_NCPAINT, sent|optional },
10352     { WM_GETTEXT, sent|defwinproc|optional },
10353     { WM_ERASEBKGND, sent|optional },
10354     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10355     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10356     { WM_NCPAINT, sent|optional },
10357     { WM_GETTEXT, sent|defwinproc|optional },
10358     { WM_ERASEBKGND, sent|optional },
10359     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10360     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10361     { 0 }
10362 };
10363
10364 static void test_SetWindowRgn(void)
10365 {
10366     HRGN hrgn;
10367     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10368                                 100, 100, 200, 200, 0, 0, 0, NULL);
10369     ok( hwnd != 0, "Failed to create overlapped window\n" );
10370
10371     ShowWindow( hwnd, SW_SHOW );
10372     UpdateWindow( hwnd );
10373     flush_events();
10374     flush_sequence();
10375
10376     trace("testing SetWindowRgn\n");
10377     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10378     SetWindowRgn( hwnd, hrgn, TRUE );
10379     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10380
10381     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10382     SetWindowRgn( hwnd, hrgn, FALSE );
10383     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10384
10385     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10386     SetWindowRgn( hwnd, hrgn, TRUE );
10387     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10388
10389     SetWindowRgn( hwnd, 0, TRUE );
10390     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10391
10392     DestroyWindow( hwnd );
10393 }
10394
10395 /*************************** ShowWindow() test ******************************/
10396 static const struct message WmShowNormal[] = {
10397     { WM_SHOWWINDOW, sent|wparam, 1 },
10398     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10399     { HCBT_ACTIVATE, hook },
10400     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10401     { HCBT_SETFOCUS, hook },
10402     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10403     { 0 }
10404 };
10405 static const struct message WmShow[] = {
10406     { WM_SHOWWINDOW, sent|wparam, 1 },
10407     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10408     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10409     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10410     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10411     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10412     { 0 }
10413 };
10414 static const struct message WmShowNoActivate_1[] = {
10415     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10416     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10417     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10418     { WM_MOVE, sent|defwinproc|optional },
10419     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10420     { 0 }
10421 };
10422 static const struct message WmShowNoActivate_2[] = {
10423     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10424     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10425     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10426     { WM_MOVE, sent|defwinproc },
10427     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10428     { HCBT_SETFOCUS, hook|optional },
10429     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10430     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10431     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10432     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10433     { 0 }
10434 };
10435 static const struct message WmShowNA_1[] = {
10436     { WM_SHOWWINDOW, sent|wparam, 1 },
10437     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10438     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10439     { 0 }
10440 };
10441 static const struct message WmShowNA_2[] = {
10442     { WM_SHOWWINDOW, sent|wparam, 1 },
10443     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10444     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10445     { 0 }
10446 };
10447 static const struct message WmRestore_1[] = {
10448     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10449     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10450     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10451     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10452     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10453     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10454     { WM_MOVE, sent|defwinproc },
10455     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10456     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10457     { 0 }
10458 };
10459 static const struct message WmRestore_2[] = {
10460     { WM_SHOWWINDOW, sent|wparam, 1 },
10461     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10462     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10463     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10464     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10465     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10466     { 0 }
10467 };
10468 static const struct message WmRestore_3[] = {
10469     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10470     { WM_GETMINMAXINFO, sent },
10471     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10472     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10473     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10474     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10475     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10476     { WM_MOVE, sent|defwinproc },
10477     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10478     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10479     { 0 }
10480 };
10481 static const struct message WmRestore_4[] = {
10482     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10483     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10484     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10485     { WM_MOVE, sent|defwinproc|optional },
10486     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10487     { 0 }
10488 };
10489 static const struct message WmRestore_5[] = {
10490     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10491     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10492     { HCBT_ACTIVATE, hook|optional },
10493     { HCBT_SETFOCUS, hook|optional },
10494     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10495     { WM_MOVE, sent|defwinproc|optional },
10496     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10497     { 0 }
10498 };
10499 static const struct message WmHide_1[] = {
10500     { WM_SHOWWINDOW, sent|wparam, 0 },
10501     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10502     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10503     { HCBT_ACTIVATE, hook|optional },
10504     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10505     { 0 }
10506 };
10507 static const struct message WmHide_2[] = {
10508     { WM_SHOWWINDOW, sent|wparam, 0 },
10509     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10510     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10511     { HCBT_ACTIVATE, hook|optional },
10512     { 0 }
10513 };
10514 static const struct message WmHide_3[] = {
10515     { WM_SHOWWINDOW, sent|wparam, 0 },
10516     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10517     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10518     { HCBT_SETFOCUS, hook|optional },
10519     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10520     { 0 }
10521 };
10522 static const struct message WmShowMinimized_1[] = {
10523     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10524     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10525     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10526     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10527     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10528     { WM_MOVE, sent|defwinproc },
10529     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10530     { 0 }
10531 };
10532 static const struct message WmMinimize_1[] = {
10533     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10534     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10535     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10536     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10537     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10538     { WM_MOVE, sent|defwinproc },
10539     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10540     { 0 }
10541 };
10542 static const struct message WmMinimize_2[] = {
10543     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10544     { HCBT_SETFOCUS, hook|optional },
10545     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10546     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10547     { WM_MOVE, sent|defwinproc },
10548     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10549     { 0 }
10550 };
10551 static const struct message WmMinimize_3[] = {
10552     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10553     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10554     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10555     { WM_MOVE, sent|defwinproc },
10556     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10557     { 0 }
10558 };
10559 static const struct message WmShowMinNoActivate[] = {
10560     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10561     { WM_WINDOWPOSCHANGING, sent },
10562     { WM_WINDOWPOSCHANGED, sent },
10563     { WM_MOVE, sent|defwinproc|optional },
10564     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10565     { 0 }
10566 };
10567 static const struct message WmMinMax_1[] = {
10568     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10569     { 0 }
10570 };
10571 static const struct message WmMinMax_2[] = {
10572     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10573     { WM_GETMINMAXINFO, sent|optional },
10574     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10575     { HCBT_ACTIVATE, hook|optional },
10576     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10577     { HCBT_SETFOCUS, hook|optional },
10578     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10579     { WM_MOVE, sent|defwinproc|optional },
10580     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10581     { HCBT_SETFOCUS, hook|optional },
10582     { 0 }
10583 };
10584 static const struct message WmMinMax_3[] = {
10585     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10586     { HCBT_SETFOCUS, hook|optional },
10587     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10588     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10589     { WM_MOVE, sent|defwinproc|optional },
10590     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10591     { 0 }
10592 };
10593 static const struct message WmMinMax_4[] = {
10594     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10595     { 0 }
10596 };
10597 static const struct message WmShowMaximized_1[] = {
10598     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10599     { WM_GETMINMAXINFO, sent },
10600     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10601     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10602     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10603     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10604     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10605     { WM_MOVE, sent|defwinproc },
10606     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10607     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10608     { 0 }
10609 };
10610 static const struct message WmShowMaximized_2[] = {
10611     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10612     { WM_GETMINMAXINFO, sent },
10613     { WM_WINDOWPOSCHANGING, sent|optional },
10614     { HCBT_ACTIVATE, hook|optional },
10615     { WM_WINDOWPOSCHANGED, sent|optional },
10616     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10617     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10618     { WM_WINDOWPOSCHANGING, sent|optional },
10619     { HCBT_SETFOCUS, hook|optional },
10620     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10621     { WM_MOVE, sent|defwinproc },
10622     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10623     { HCBT_SETFOCUS, hook|optional },
10624     { 0 }
10625 };
10626 static const struct message WmShowMaximized_3[] = {
10627     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10628     { WM_GETMINMAXINFO, sent|optional },
10629     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10630     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10631     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10632     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10633     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10634     { WM_MOVE, sent|defwinproc|optional },
10635     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10636     { 0 }
10637 };
10638
10639 static void test_ShowWindow(void)
10640 {
10641     /* ShowWindow commands in random order */
10642     static const struct
10643     {
10644         INT cmd; /* ShowWindow command */
10645         LPARAM ret; /* ShowWindow return value */
10646         DWORD style; /* window style after the command */
10647         const struct message *msg; /* message sequence the command produces */
10648         INT wp_cmd, wp_flags; /* window placement after the command */
10649         POINT wp_min, wp_max; /* window placement after the command */
10650         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10651     } sw[] =
10652     {
10653 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
10654            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10655 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
10656            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10657 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
10658            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10659 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10660            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10661 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
10662            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10663 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
10664            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10665 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
10666            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10667 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10668            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10669 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
10670            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10671 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10672            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10673 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
10674            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10675 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
10676            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10677 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
10678            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10679 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10680            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10681 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
10682            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10683 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10684            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10685 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
10686            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10687 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10688            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10689 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10690            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10691 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10692            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10693 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10694            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10695 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
10696            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
10697 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
10698            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10699 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10700            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10701 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10702            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10703 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
10704            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10705 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
10706            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10707 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10708            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10709 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10710            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10711 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
10712            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10713 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10714            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10715 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
10716            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10717 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10718            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10719 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
10720            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10721 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
10722            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10723 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10724            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10725 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
10726            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10727 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10728            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10729 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10730            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10731 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
10732            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10733 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10734            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10735 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
10736            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10737 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10738            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10739 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10740            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10741 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10742            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10743 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
10744            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10745 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
10746            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10747 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
10748            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10749 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
10750            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10751 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10752            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10753 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10754            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10755 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
10756            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10757 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10758            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10759 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
10760            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10761 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10762            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10763 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
10764            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10765 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10766            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
10767     };
10768     HWND hwnd;
10769     DWORD style;
10770     LPARAM ret;
10771     INT i;
10772     WINDOWPLACEMENT wp;
10773     RECT win_rc, work_rc = {0, 0, 0, 0};
10774
10775 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10776     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10777                           120, 120, 90, 90,
10778                           0, 0, 0, NULL);
10779     assert(hwnd);
10780
10781     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10782     ok(style == 0, "expected style 0, got %08x\n", style);
10783
10784     flush_events();
10785     flush_sequence();
10786
10787     if (pGetMonitorInfoA && pMonitorFromPoint)
10788     {
10789         HMONITOR hmon;
10790         MONITORINFO mi;
10791         POINT pt = {0, 0};
10792
10793         SetLastError(0xdeadbeef);
10794         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
10795         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
10796
10797         mi.cbSize = sizeof(mi);
10798         SetLastError(0xdeadbeef);
10799         ret = pGetMonitorInfoA(hmon, &mi);
10800         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
10801         trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
10802             mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
10803             mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
10804         work_rc = mi.rcWork;
10805     }
10806
10807     GetWindowRect(hwnd, &win_rc);
10808     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
10809
10810     wp.length = sizeof(wp);
10811     SetLastError(0xdeadbeaf);
10812     ret = GetWindowPlacement(hwnd, &wp);
10813     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
10814     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
10815     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
10816     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
10817        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
10818     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
10819        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
10820     if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
10821     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10822        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10823         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10824         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10825         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10826     else
10827     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10828        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10829         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10830         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10831         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10832
10833     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10834     {
10835         static const char * const sw_cmd_name[13] =
10836         {
10837             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10838             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10839             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10840             "SW_NORMALNA" /* 0xCC */
10841         };
10842         char comment[64];
10843         INT idx; /* index into the above array of names */
10844
10845         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10846
10847         style = GetWindowLong(hwnd, GWL_STYLE);
10848         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10849         ret = ShowWindow(hwnd, sw[i].cmd);
10850         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10851         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10852         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10853
10854         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10855         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10856
10857         wp.length = sizeof(wp);
10858         SetLastError(0xdeadbeaf);
10859         ret = GetWindowPlacement(hwnd, &wp);
10860         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
10861         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
10862         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
10863
10864         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
10865         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
10866             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
10867         {
10868             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
10869                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
10870                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
10871         }
10872         else
10873         {
10874             if (wp.ptMinPosition.x != sw[i].wp_min.x || wp.ptMinPosition.y != sw[i].wp_min.y)
10875             todo_wine
10876             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
10877                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
10878             else
10879             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
10880                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
10881         }
10882
10883         if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
10884         todo_wine
10885         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
10886            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
10887         else
10888         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
10889            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
10890
10891 if (0) /* FIXME: Wine behaves completely different here */
10892         ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10893            "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10894             win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10895             wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10896             wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10897
10898         flush_events();
10899         flush_sequence();
10900     }
10901
10902     DestroyWindow(hwnd);
10903 }
10904
10905 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10906 {
10907     struct recvd_message msg;
10908
10909     if (ignore_message( message )) return 0;
10910
10911     msg.hwnd = hwnd;
10912     msg.message = message;
10913     msg.flags = sent|wparam|lparam;
10914     msg.wParam = wParam;
10915     msg.lParam = lParam;
10916     msg.descr = "dialog";
10917     add_message(&msg);
10918
10919     /* calling DefDlgProc leads to a recursion under XP */
10920
10921     switch (message)
10922     {
10923     case WM_INITDIALOG:
10924     case WM_GETDLGCODE:
10925         return 0;
10926     }
10927     return 1;
10928 }
10929
10930 static const struct message WmDefDlgSetFocus_1[] = {
10931     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10932     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10933     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10934     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10935     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10936     { HCBT_SETFOCUS, hook },
10937     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10938     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10939     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10940     { WM_SETFOCUS, sent|wparam, 0 },
10941     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10942     { WM_CTLCOLOREDIT, sent },
10943     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10944     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10945     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10946     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10947     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10948     { 0 }
10949 };
10950 static const struct message WmDefDlgSetFocus_2[] = {
10951     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10952     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10953     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10954     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10955     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10956     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10957     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10958     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10959     { 0 }
10960 };
10961 /* Creation of a dialog */
10962 static const struct message WmCreateDialogParamSeq_1[] = {
10963     { HCBT_CREATEWND, hook },
10964     { WM_NCCREATE, sent },
10965     { WM_NCCALCSIZE, sent|wparam, 0 },
10966     { WM_CREATE, sent },
10967     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10968     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10969     { WM_MOVE, sent },
10970     { WM_SETFONT, sent },
10971     { WM_INITDIALOG, sent },
10972     { WM_CHANGEUISTATE, sent|optional },
10973     { 0 }
10974 };
10975 /* Creation of a dialog */
10976 static const struct message WmCreateDialogParamSeq_2[] = {
10977     { HCBT_CREATEWND, hook },
10978     { WM_NCCREATE, sent },
10979     { WM_NCCALCSIZE, sent|wparam, 0 },
10980     { WM_CREATE, sent },
10981     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10982     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10983     { WM_MOVE, sent },
10984     { WM_CHANGEUISTATE, sent|optional },
10985     { 0 }
10986 };
10987
10988 static void test_dialog_messages(void)
10989 {
10990     WNDCLASS cls;
10991     HWND hdlg, hedit1, hedit2, hfocus;
10992     LRESULT ret;
10993
10994 #define set_selection(hctl, start, end) \
10995     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10996     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10997
10998 #define check_selection(hctl, start, end) \
10999     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
11000     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11001
11002     subclass_edit();
11003
11004     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11005                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11006                           0, 0, 100, 100, 0, 0, 0, NULL);
11007     ok(hdlg != 0, "Failed to create custom dialog window\n");
11008
11009     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
11010                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11011                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11012     ok(hedit1 != 0, "Failed to create edit control\n");
11013     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
11014                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11015                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11016     ok(hedit2 != 0, "Failed to create edit control\n");
11017
11018     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11019     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11020
11021     hfocus = GetFocus();
11022     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11023
11024     SetFocus(hedit2);
11025     hfocus = GetFocus();
11026     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11027
11028     check_selection(hedit1, 0, 0);
11029     check_selection(hedit2, 0, 0);
11030
11031     set_selection(hedit2, 0, -1);
11032     check_selection(hedit2, 0, 3);
11033
11034     SetFocus(0);
11035     hfocus = GetFocus();
11036     ok(hfocus == 0, "wrong focus %p\n", hfocus);
11037
11038     flush_sequence();
11039     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11040     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11041     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11042
11043     hfocus = GetFocus();
11044     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11045
11046     check_selection(hedit1, 0, 5);
11047     check_selection(hedit2, 0, 3);
11048
11049     flush_sequence();
11050     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11051     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11052     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11053
11054     hfocus = GetFocus();
11055     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11056
11057     check_selection(hedit1, 0, 5);
11058     check_selection(hedit2, 0, 3);
11059
11060     EndDialog(hdlg, 0);
11061     DestroyWindow(hedit1);
11062     DestroyWindow(hedit2);
11063     DestroyWindow(hdlg);
11064     flush_sequence();
11065
11066 #undef set_selection
11067 #undef check_selection
11068
11069     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
11070     cls.lpszClassName = "MyDialogClass";
11071     cls.hInstance = GetModuleHandle(0);
11072     /* need a cast since a dlgproc is used as a wndproc */
11073     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
11074     if (!RegisterClass(&cls)) assert(0);
11075
11076     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11077     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11078     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11079     EndDialog(hdlg, 0);
11080     DestroyWindow(hdlg);
11081     flush_sequence();
11082
11083     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11084     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11085     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11086     EndDialog(hdlg, 0);
11087     DestroyWindow(hdlg);
11088     flush_sequence();
11089
11090     UnregisterClass(cls.lpszClassName, cls.hInstance);
11091 }
11092
11093 static void test_nullCallback(void)
11094 {
11095     HWND hwnd;
11096
11097     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11098                            100, 100, 200, 200, 0, 0, 0, NULL);
11099     ok (hwnd != 0, "Failed to create overlapped window\n");
11100
11101     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11102     flush_events();
11103     DestroyWindow(hwnd);
11104 }
11105
11106 /* SetActiveWindow( 0 ) hwnd visible */
11107 static const struct message SetActiveWindowSeq0[] =
11108 {
11109     { HCBT_ACTIVATE, hook|optional },
11110     { WM_NCACTIVATE, sent|wparam, 0 },
11111     { WM_GETTEXT, sent|defwinproc|optional },
11112     { WM_ACTIVATE, sent|wparam, 0 },
11113     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11114     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11115     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11116     { WM_KILLFOCUS, sent|optional },
11117     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11118     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11119     { WM_NCACTIVATE, sent|wparam|optional, 1 },
11120     { WM_GETTEXT, sent|defwinproc|optional },
11121     { WM_ACTIVATE, sent|wparam|optional, 1 },
11122     { HCBT_SETFOCUS, hook|optional },
11123     { WM_KILLFOCUS, sent|defwinproc|optional },
11124     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11125     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11126     { WM_IME_SETCONTEXT, sent|optional },
11127     { WM_IME_SETCONTEXT, sent|optional },
11128     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11129     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11130     { WM_SETFOCUS, sent|defwinproc|optional },
11131     { WM_GETTEXT, sent|optional },
11132     { 0 }
11133 };
11134 /* SetActiveWindow( hwnd ) hwnd visible */
11135 static const struct message SetActiveWindowSeq1[] =
11136 {
11137     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11138     { 0 }
11139 };
11140 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11141 static const struct message SetActiveWindowSeq2[] =
11142 {
11143     { HCBT_ACTIVATE, hook },
11144     { WM_NCACTIVATE, sent|wparam, 0 },
11145     { WM_GETTEXT, sent|defwinproc|optional },
11146     { WM_ACTIVATE, sent|wparam, 0 },
11147     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11148     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11149     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11150     { WM_NCPAINT, sent|optional },
11151     { WM_GETTEXT, sent|defwinproc|optional },
11152     { WM_ERASEBKGND, sent|optional },
11153     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11154     { WM_NCACTIVATE, sent|wparam, 1 },
11155     { WM_GETTEXT, sent|defwinproc|optional },
11156     { WM_ACTIVATE, sent|wparam, 1 },
11157     { HCBT_SETFOCUS, hook },
11158     { WM_KILLFOCUS, sent|defwinproc },
11159     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11160     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11161     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11162     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11163     { WM_SETFOCUS, sent|defwinproc },
11164     { WM_GETTEXT, sent|optional },
11165     { 0 }
11166 };
11167
11168 /* SetActiveWindow( hwnd ) hwnd not visible */
11169 static const struct message SetActiveWindowSeq3[] =
11170 {
11171     { HCBT_ACTIVATE, hook },
11172     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11173     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11174     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11175     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11176     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11177     { WM_ACTIVATEAPP, sent|wparam, 1 },
11178     { WM_ACTIVATEAPP, sent|wparam, 1 },
11179     { WM_NCACTIVATE, sent|wparam, 1 },
11180     { WM_ACTIVATE, sent|wparam, 1 },
11181     { HCBT_SETFOCUS, hook },
11182     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11183     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11184     { WM_SETFOCUS, sent|defwinproc },
11185     { 0 }
11186 };
11187 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11188 static const struct message SetActiveWindowSeq4[] =
11189 {
11190     { HCBT_ACTIVATE, hook },
11191     { WM_NCACTIVATE, sent|wparam, 0 },
11192     { WM_GETTEXT, sent|defwinproc|optional },
11193     { WM_ACTIVATE, sent|wparam, 0 },
11194     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11195     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11196     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11197     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11198     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11199     { WM_NCACTIVATE, sent|wparam, 1 },
11200     { WM_GETTEXT, sent|defwinproc|optional },
11201     { WM_ACTIVATE, sent|wparam, 1 },
11202     { HCBT_SETFOCUS, hook },
11203     { WM_KILLFOCUS, sent|defwinproc },
11204     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11205     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11206     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11207     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11208     { WM_SETFOCUS, sent|defwinproc },
11209     { 0 }
11210 };
11211
11212
11213 static void test_SetActiveWindow(void)
11214 {
11215     HWND hwnd, popup, ret;
11216
11217     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11218                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11219                            100, 100, 200, 200, 0, 0, 0, NULL);
11220
11221     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11222                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11223                            100, 100, 200, 200, hwnd, 0, 0, NULL);
11224
11225     ok(hwnd != 0, "Failed to create overlapped window\n");
11226     ok(popup != 0, "Failed to create popup window\n");
11227     SetForegroundWindow( popup );
11228     flush_sequence();
11229
11230     trace("SetActiveWindow(0)\n");
11231     ret = SetActiveWindow(0);
11232     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11233     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11234     flush_sequence();
11235
11236     trace("SetActiveWindow(hwnd), hwnd visible\n");
11237     ret = SetActiveWindow(hwnd);
11238     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11239     flush_sequence();
11240
11241     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11242     ret = SetActiveWindow(popup);
11243     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11244     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11245     flush_sequence();
11246
11247     ShowWindow(hwnd, SW_HIDE);
11248     ShowWindow(popup, SW_HIDE);
11249     flush_sequence();
11250
11251     trace("SetActiveWindow(hwnd), hwnd not visible\n");
11252     ret = SetActiveWindow(hwnd);
11253     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11254     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11255     flush_sequence();
11256
11257     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11258     ret = SetActiveWindow(popup);
11259     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11260     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11261     flush_sequence();
11262
11263     trace("done\n");
11264
11265     DestroyWindow(hwnd);
11266 }
11267
11268 static const struct message SetForegroundWindowSeq[] =
11269 {
11270     { WM_NCACTIVATE, sent|wparam, 0 },
11271     { WM_GETTEXT, sent|defwinproc|optional },
11272     { WM_ACTIVATE, sent|wparam, 0 },
11273     { WM_ACTIVATEAPP, sent|wparam, 0 },
11274     { WM_KILLFOCUS, sent },
11275     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11276     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11277     { 0 }
11278 };
11279
11280 static void test_SetForegroundWindow(void)
11281 {
11282     HWND hwnd;
11283
11284     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11285                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11286                            100, 100, 200, 200, 0, 0, 0, NULL);
11287     ok (hwnd != 0, "Failed to create overlapped window\n");
11288     SetForegroundWindow( hwnd );
11289     flush_sequence();
11290
11291     trace("SetForegroundWindow( 0 )\n");
11292     SetForegroundWindow( 0 );
11293     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11294     trace("SetForegroundWindow( GetDesktopWindow() )\n");
11295     SetForegroundWindow( GetDesktopWindow() );
11296     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11297                                         "foreground top level window", FALSE);
11298     trace("done\n");
11299
11300     DestroyWindow(hwnd);
11301 }
11302
11303 static void test_dbcs_wm_char(void)
11304 {
11305     BYTE dbch[2];
11306     WCHAR wch, bad_wch;
11307     HWND hwnd, hwnd2;
11308     MSG msg;
11309     DWORD time;
11310     POINT pt;
11311     DWORD_PTR res;
11312     CPINFOEXA cpinfo;
11313     UINT i, j, k;
11314     struct message wmCharSeq[2];
11315
11316     if (!pGetCPInfoExA)
11317     {
11318         win_skip("GetCPInfoExA is not available\n");
11319         return;
11320     }
11321
11322     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11323     if (cpinfo.MaxCharSize != 2)
11324     {
11325         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11326         return;
11327     }
11328
11329     dbch[0] = dbch[1] = 0;
11330     wch = 0;
11331     bad_wch = cpinfo.UnicodeDefaultChar;
11332     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11333         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11334             for (k = 128; k <= 255; k++)
11335             {
11336                 char str[2];
11337                 WCHAR wstr[2];
11338                 str[0] = j;
11339                 str[1] = k;
11340                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11341                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11342                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
11343                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11344                 {
11345                     dbch[0] = j;
11346                     dbch[1] = k;
11347                     wch = wstr[0];
11348                     break;
11349                 }
11350             }
11351
11352     if (!wch)
11353     {
11354         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11355         return;
11356     }
11357     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11358            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11359
11360     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11361                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11362     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11363                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11364     ok (hwnd != 0, "Failed to create overlapped window\n");
11365     ok (hwnd2 != 0, "Failed to create overlapped window\n");
11366     flush_sequence();
11367
11368     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11369     wmCharSeq[0].message = WM_CHAR;
11370     wmCharSeq[0].flags = sent|wparam;
11371     wmCharSeq[0].wParam = wch;
11372
11373     /* posted message */
11374     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11375     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11376     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11377     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11378     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11379     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11380     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11381
11382     /* posted thread message */
11383     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11384     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11385     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11386     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11387     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11388     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11389     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11390
11391     /* sent message */
11392     flush_sequence();
11393     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11394     ok_sequence( WmEmptySeq, "no messages", FALSE );
11395     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11396     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11397     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11398
11399     /* sent message with timeout */
11400     flush_sequence();
11401     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11402     ok_sequence( WmEmptySeq, "no messages", FALSE );
11403     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11404     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11405     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11406
11407     /* sent message with timeout and callback */
11408     flush_sequence();
11409     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11410     ok_sequence( WmEmptySeq, "no messages", FALSE );
11411     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11412     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11413     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11414
11415     /* sent message with callback */
11416     flush_sequence();
11417     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11418     ok_sequence( WmEmptySeq, "no messages", FALSE );
11419     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11420     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11421     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11422
11423     /* direct window proc call */
11424     flush_sequence();
11425     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11426     ok_sequence( WmEmptySeq, "no messages", FALSE );
11427     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11428     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11429
11430     /* dispatch message */
11431     msg.hwnd = hwnd;
11432     msg.message = WM_CHAR;
11433     msg.wParam = dbch[0];
11434     msg.lParam = 0;
11435     DispatchMessageA( &msg );
11436     ok_sequence( WmEmptySeq, "no messages", FALSE );
11437     msg.wParam = dbch[1];
11438     DispatchMessageA( &msg );
11439     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11440
11441     /* window handle is irrelevant */
11442     flush_sequence();
11443     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11444     ok_sequence( WmEmptySeq, "no messages", FALSE );
11445     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11446     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11447     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11448
11449     /* interleaved post and send */
11450     flush_sequence();
11451     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11452     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11453     ok_sequence( WmEmptySeq, "no messages", FALSE );
11454     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11455     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11456     ok_sequence( WmEmptySeq, "no messages", FALSE );
11457     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11458     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11459     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11460     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11461     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11462     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11463     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11464
11465     /* interleaved sent message and winproc */
11466     flush_sequence();
11467     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11468     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11469     ok_sequence( WmEmptySeq, "no messages", FALSE );
11470     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11471     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11472     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11473     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11474
11475     /* interleaved winproc and dispatch */
11476     msg.hwnd = hwnd;
11477     msg.message = WM_CHAR;
11478     msg.wParam = dbch[0];
11479     msg.lParam = 0;
11480     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11481     DispatchMessageA( &msg );
11482     ok_sequence( WmEmptySeq, "no messages", FALSE );
11483     msg.wParam = dbch[1];
11484     DispatchMessageA( &msg );
11485     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11486     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11487     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11488
11489     /* interleaved sends */
11490     flush_sequence();
11491     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11492     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11493     ok_sequence( WmEmptySeq, "no messages", FALSE );
11494     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11495     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11496     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11497     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11498
11499     /* dbcs WM_CHAR */
11500     flush_sequence();
11501     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11502     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11503     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11504
11505     /* other char messages are not magic */
11506     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11507     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11508     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11509     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11510     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11511     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11512     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11513     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11514     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11515     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11516
11517     /* test retrieving messages */
11518
11519     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11520     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11521     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11522     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11523     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11524     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11525     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11526     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11527     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11528     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11529
11530     /* message filters */
11531     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11532     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11533     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11534     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11535     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11536     /* message id is filtered, hwnd is not */
11537     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
11538     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
11539     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11540     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11541     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11542     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11543
11544     /* mixing GetMessage and PostMessage */
11545     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11546     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
11547     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11548     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11549     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11550     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11551     time = msg.time;
11552     pt = msg.pt;
11553     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11554     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11555     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11556     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11557     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11558     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11559     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11560     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 );
11561     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11562
11563     /* without PM_REMOVE */
11564     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11565     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11566     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11567     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11568     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11569     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11570     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11571     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11572     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11573     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11574     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11575     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11576     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11577     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11578     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11579     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11580     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11581     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11582
11583     DestroyWindow(hwnd);
11584     DestroyWindow(hwnd2);
11585 }
11586
11587 #define ID_LISTBOX 0x000f
11588
11589 static const struct message wm_lb_setcursel_0[] =
11590 {
11591     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11592     { WM_CTLCOLORLISTBOX, sent|parent },
11593     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11594     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11595     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11596     { 0 }
11597 };
11598 static const struct message wm_lb_setcursel_1[] =
11599 {
11600     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11601     { WM_CTLCOLORLISTBOX, sent|parent },
11602     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11603     { WM_CTLCOLORLISTBOX, sent|parent },
11604     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11605     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11606     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11607     { 0 }
11608 };
11609 static const struct message wm_lb_setcursel_2[] =
11610 {
11611     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11612     { WM_CTLCOLORLISTBOX, sent|parent },
11613     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11614     { WM_CTLCOLORLISTBOX, sent|parent },
11615     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11616     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11617     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11618     { 0 }
11619 };
11620 static const struct message wm_lb_click_0[] =
11621 {
11622     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11623     { HCBT_SETFOCUS, hook },
11624     { WM_KILLFOCUS, sent|parent },
11625     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11626     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11627     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11628     { WM_SETFOCUS, sent|defwinproc },
11629
11630     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11631     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11632     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11633     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11634     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11635
11636     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11637     { WM_CTLCOLORLISTBOX, sent|parent },
11638     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11639     { WM_CTLCOLORLISTBOX, sent|parent },
11640     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11641     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11642
11643     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11644     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11645
11646     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11647     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11648     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11649     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11650     { 0 }
11651 };
11652 static const struct message wm_lb_deletestring[] =
11653 {
11654     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11655     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11656     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11657     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11658     { 0 }
11659 };
11660 static const struct message wm_lb_deletestring_reset[] =
11661 {
11662     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11663     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11664     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11665     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11666     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11667     { 0 }
11668 };
11669
11670 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11671
11672 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11673
11674 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11675 {
11676     static LONG defwndproc_counter = 0;
11677     LRESULT ret;
11678     struct recvd_message msg;
11679
11680     /* do not log painting messages */
11681     if (message != WM_PAINT &&
11682         message != WM_NCPAINT &&
11683         message != WM_SYNCPAINT &&
11684         message != WM_ERASEBKGND &&
11685         message != WM_NCHITTEST &&
11686         message != WM_GETTEXT &&
11687         !ignore_message( message ))
11688     {
11689         msg.hwnd = hwnd;
11690         msg.message = message;
11691         msg.flags = sent|wparam|lparam;
11692         if (defwndproc_counter) msg.flags |= defwinproc;
11693         msg.wParam = wp;
11694         msg.lParam = lp;
11695         msg.descr = "listbox";
11696         add_message(&msg);
11697     }
11698
11699     defwndproc_counter++;
11700     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11701     defwndproc_counter--;
11702
11703     return ret;
11704 }
11705
11706 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11707                                int caret_index, int top_index, int line)
11708 {
11709     LRESULT ret;
11710
11711     /* calling an orig proc helps to avoid unnecessary message logging */
11712     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11713     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11714     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11715     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11716     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11717     ok_(__FILE__, line)(ret == caret_index ||
11718                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11719                         "expected caret index %d, got %ld\n", caret_index, ret);
11720     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11721     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11722 }
11723
11724 static void test_listbox_messages(void)
11725 {
11726     HWND parent, listbox;
11727     LRESULT ret;
11728
11729     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11730                              100, 100, 200, 200, 0, 0, 0, NULL);
11731     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11732                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11733                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11734     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11735
11736     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11737
11738     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11739     ok(ret == 0, "expected 0, got %ld\n", ret);
11740     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11741     ok(ret == 1, "expected 1, got %ld\n", ret);
11742     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11743     ok(ret == 2, "expected 2, got %ld\n", ret);
11744
11745     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11746
11747     flush_sequence();
11748
11749     log_all_parent_messages++;
11750
11751     trace("selecting item 0\n");
11752     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11753     ok(ret == 0, "expected 0, got %ld\n", ret);
11754     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11755     check_lb_state(listbox, 3, 0, 0, 0);
11756     flush_sequence();
11757
11758     trace("selecting item 1\n");
11759     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11760     ok(ret == 1, "expected 1, got %ld\n", ret);
11761     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11762     check_lb_state(listbox, 3, 1, 1, 0);
11763
11764     trace("selecting item 2\n");
11765     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11766     ok(ret == 2, "expected 2, got %ld\n", ret);
11767     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11768     check_lb_state(listbox, 3, 2, 2, 0);
11769
11770     trace("clicking on item 0\n");
11771     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11772     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11773     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11774     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11775     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11776     check_lb_state(listbox, 3, 0, 0, 0);
11777     flush_sequence();
11778
11779     trace("deleting item 0\n");
11780     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11781     ok(ret == 2, "expected 2, got %ld\n", ret);
11782     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11783     check_lb_state(listbox, 2, -1, 0, 0);
11784     flush_sequence();
11785
11786     trace("deleting item 0\n");
11787     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11788     ok(ret == 1, "expected 1, got %ld\n", ret);
11789     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11790     check_lb_state(listbox, 1, -1, 0, 0);
11791     flush_sequence();
11792
11793     trace("deleting item 0\n");
11794     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11795     ok(ret == 0, "expected 0, got %ld\n", ret);
11796     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11797     check_lb_state(listbox, 0, -1, 0, 0);
11798     flush_sequence();
11799
11800     trace("deleting item 0\n");
11801     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11802     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11803     check_lb_state(listbox, 0, -1, 0, 0);
11804     flush_sequence();
11805
11806     log_all_parent_messages--;
11807
11808     DestroyWindow(listbox);
11809     DestroyWindow(parent);
11810 }
11811
11812 /*************************** Menu test ******************************/
11813 static const struct message wm_popup_menu_1[] =
11814 {
11815     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11816     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11817     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11818     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11819     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11820     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11821     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11822     { WM_INITMENU, sent|lparam, 0, 0 },
11823     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11824     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11825     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11826     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11827     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11828     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11829     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
11830     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11831     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11832     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11833     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11834     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11835     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11836     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11837     { 0 }
11838 };
11839 static const struct message wm_popup_menu_2[] =
11840 {
11841     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11842     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11843     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11844     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11845     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11846     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11847     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11848     { WM_INITMENU, sent|lparam, 0, 0 },
11849     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11850     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11851     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11852     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11853     { HCBT_CREATEWND, hook },
11854     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11855                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11856     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11857     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11858     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11859     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11860     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11861     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11862     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11863     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11864     { HCBT_DESTROYWND, hook },
11865     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11866     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11867     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11868     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11869     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11870     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11871     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11872     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11873     { 0 }
11874 };
11875 static const struct message wm_popup_menu_3[] =
11876 {
11877     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11878     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11879     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11880     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11881     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11882     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11883     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11884     { WM_INITMENU, sent|lparam, 0, 0 },
11885     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11886     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11887     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11888     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11889     { HCBT_CREATEWND, hook },
11890     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11891                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11892     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11893     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11894     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11895     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11896     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11897     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11898     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11899     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11900     { HCBT_DESTROYWND, hook },
11901     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11902     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11903     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11904     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11905     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11906     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11907     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11908     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11909     { 0 }
11910 };
11911
11912 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11913 {
11914     if (message == WM_ENTERIDLE ||
11915         message == WM_INITMENU ||
11916         message == WM_INITMENUPOPUP ||
11917         message == WM_MENUSELECT ||
11918         message == WM_PARENTNOTIFY ||
11919         message == WM_ENTERMENULOOP ||
11920         message == WM_EXITMENULOOP ||
11921         message == WM_UNINITMENUPOPUP ||
11922         message == WM_KEYDOWN ||
11923         message == WM_KEYUP ||
11924         message == WM_CHAR ||
11925         message == WM_SYSKEYDOWN ||
11926         message == WM_SYSKEYUP ||
11927         message == WM_SYSCHAR ||
11928         message == WM_COMMAND ||
11929         message == WM_MENUCOMMAND)
11930     {
11931         struct recvd_message msg;
11932
11933         msg.hwnd = hwnd;
11934         msg.message = message;
11935         msg.flags = sent|wparam|lparam;
11936         msg.wParam = wp;
11937         msg.lParam = lp;
11938         msg.descr = "parent_menu_proc";
11939         add_message(&msg);
11940     }
11941
11942     return DefWindowProcA(hwnd, message, wp, lp);
11943 }
11944
11945 static void set_menu_style(HMENU hmenu, DWORD style)
11946 {
11947     MENUINFO mi;
11948     BOOL ret;
11949
11950     mi.cbSize = sizeof(mi);
11951     mi.fMask = MIM_STYLE;
11952     mi.dwStyle = style;
11953     SetLastError(0xdeadbeef);
11954     ret = pSetMenuInfo(hmenu, &mi);
11955     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11956 }
11957
11958 static DWORD get_menu_style(HMENU hmenu)
11959 {
11960     MENUINFO mi;
11961     BOOL ret;
11962
11963     mi.cbSize = sizeof(mi);
11964     mi.fMask = MIM_STYLE;
11965     mi.dwStyle = 0;
11966     SetLastError(0xdeadbeef);
11967     ret = pGetMenuInfo(hmenu, &mi);
11968     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11969
11970     return mi.dwStyle;
11971 }
11972
11973 static void test_menu_messages(void)
11974 {
11975     MSG msg;
11976     WNDCLASSA cls;
11977     HMENU hmenu, hmenu_popup;
11978     HWND hwnd;
11979     DWORD style;
11980
11981     if (!pGetMenuInfo || !pSetMenuInfo)
11982     {
11983         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11984         return;
11985     }
11986     cls.style = 0;
11987     cls.lpfnWndProc = parent_menu_proc;
11988     cls.cbClsExtra = 0;
11989     cls.cbWndExtra = 0;
11990     cls.hInstance = GetModuleHandleA(0);
11991     cls.hIcon = 0;
11992     cls.hCursor = LoadCursorA(0, IDC_ARROW);
11993     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11994     cls.lpszMenuName = NULL;
11995     cls.lpszClassName = "TestMenuClass";
11996     UnregisterClass(cls.lpszClassName, cls.hInstance);
11997     if (!RegisterClassA(&cls)) assert(0);
11998
11999     SetLastError(0xdeadbeef);
12000     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12001                            100, 100, 200, 200, 0, 0, 0, NULL);
12002     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12003
12004     SetLastError(0xdeadbeef);
12005     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
12006     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12007
12008     SetMenu(hwnd, hmenu);
12009     SetForegroundWindow( hwnd );
12010
12011     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12012     style = get_menu_style(hmenu);
12013     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12014
12015     hmenu_popup = GetSubMenu(hmenu, 0);
12016     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12017     style = get_menu_style(hmenu_popup);
12018     ok(style == 0, "expected 0, got %u\n", style);
12019
12020     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12021     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12022     style = get_menu_style(hmenu_popup);
12023     ok(style == 0, "expected 0, got %u\n", style);
12024
12025     /* Alt+E, Enter */
12026     trace("testing a popup menu command\n");
12027     flush_sequence();
12028     keybd_event(VK_MENU, 0, 0, 0);
12029     keybd_event('E', 0, 0, 0);
12030     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12031     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12032     keybd_event(VK_RETURN, 0, 0, 0);
12033     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12034     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12035     {
12036         TranslateMessage(&msg);
12037         DispatchMessage(&msg);
12038     }
12039     if (!sequence_cnt)  /* we didn't get any message */
12040     {
12041         skip( "queuing key events not supported\n" );
12042         goto done;
12043     }
12044     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12045     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12046     {
12047         win_skip( "menu tracking through VK_MENU not supported\n" );
12048         goto done;
12049     }
12050     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12051
12052     /* Alt+F, Right, Enter */
12053     trace("testing submenu of a popup menu command\n");
12054     flush_sequence();
12055     keybd_event(VK_MENU, 0, 0, 0);
12056     keybd_event('F', 0, 0, 0);
12057     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12058     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12059     keybd_event(VK_RIGHT, 0, 0, 0);
12060     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12061     keybd_event(VK_RETURN, 0, 0, 0);
12062     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12063     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12064     {
12065         TranslateMessage(&msg);
12066         DispatchMessage(&msg);
12067     }
12068     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12069
12070     set_menu_style(hmenu, 0);
12071     style = get_menu_style(hmenu);
12072     ok(style == 0, "expected 0, got %u\n", style);
12073
12074     hmenu_popup = GetSubMenu(hmenu, 0);
12075     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12076     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12077     style = get_menu_style(hmenu_popup);
12078     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12079
12080     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12081     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12082     style = get_menu_style(hmenu_popup);
12083     ok(style == 0, "expected 0, got %u\n", style);
12084
12085     /* Alt+F, Right, Enter */
12086     trace("testing submenu of a popup menu command\n");
12087     flush_sequence();
12088     keybd_event(VK_MENU, 0, 0, 0);
12089     keybd_event('F', 0, 0, 0);
12090     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12091     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12092     keybd_event(VK_RIGHT, 0, 0, 0);
12093     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12094     keybd_event(VK_RETURN, 0, 0, 0);
12095     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12096     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12097     {
12098         TranslateMessage(&msg);
12099         DispatchMessage(&msg);
12100     }
12101     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12102
12103 done:
12104     DestroyWindow(hwnd);
12105     DestroyMenu(hmenu);
12106 }
12107
12108
12109 static void test_paintingloop(void)
12110 {
12111     HWND hwnd;
12112
12113     paint_loop_done = 0;
12114     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12115                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12116                                 100, 100, 100, 100, 0, 0, 0, NULL );
12117     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12118     ShowWindow(hwnd,SW_NORMAL);
12119     SetFocus(hwnd);
12120
12121     while (!paint_loop_done)
12122     {
12123         MSG msg;
12124         if (PeekMessageA(&msg, 0, 0, 0, 1))
12125         {
12126             TranslateMessage(&msg);
12127             DispatchMessage(&msg);
12128         }
12129     }
12130     DestroyWindow(hwnd);
12131 }
12132
12133 static void test_defwinproc(void)
12134 {
12135     HWND hwnd;
12136     MSG msg;
12137     int gotwmquit = FALSE;
12138     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12139     assert(hwnd);
12140     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12141     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12142         if( msg.message == WM_QUIT) gotwmquit = TRUE;
12143         DispatchMessageA( &msg );
12144     }
12145     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
12146     DestroyWindow( hwnd);
12147 }
12148
12149 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
12150 static void clear_clipboard_(int line, HWND hWnd)
12151 {
12152     BOOL succ;
12153     succ = OpenClipboard(hWnd);
12154     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12155     succ = EmptyClipboard();
12156     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12157     succ = CloseClipboard();
12158     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12159 }
12160
12161 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12162 static void expect_HWND_(int line, HWND expected, HWND got)
12163 {
12164     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12165 }
12166
12167 static WNDPROC pOldViewerProc;
12168
12169 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12170 {
12171     static BOOL recursion_guard;
12172
12173     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12174     {
12175         recursion_guard = TRUE;
12176         clear_clipboard(hWnd);
12177         recursion_guard = FALSE;
12178     }
12179     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12180 }
12181
12182 static void test_clipboard_viewers(void)
12183 {
12184     static struct message wm_change_cb_chain[] =
12185     {
12186         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12187         { 0 }
12188     };
12189     static const struct message wm_clipboard_destroyed[] =
12190     {
12191         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12192         { 0 }
12193     };
12194     static struct message wm_clipboard_changed[] =
12195     {
12196         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12197         { 0 }
12198     };
12199     static struct message wm_clipboard_changed_and_owned[] =
12200     {
12201         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12202         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12203         { 0 }
12204     };
12205
12206     HINSTANCE hInst = GetModuleHandleA(NULL);
12207     HWND hWnd1, hWnd2, hWnd3;
12208     HWND hOrigViewer;
12209     HWND hRet;
12210
12211     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12212         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12213         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12214         GetDesktopWindow(), NULL, hInst, NULL);
12215     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12216         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12217         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12218         GetDesktopWindow(), NULL, hInst, NULL);
12219     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12220         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12221         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12222         GetDesktopWindow(), NULL, hInst, NULL);
12223     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12224     assert(hWnd1 && hWnd2 && hWnd3);
12225
12226     flush_sequence();
12227
12228     /* Test getting the clipboard viewer and setting the viewer to NULL. */
12229     hOrigViewer = GetClipboardViewer();
12230     hRet = SetClipboardViewer(NULL);
12231     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12232     expect_HWND(hOrigViewer, hRet);
12233     expect_HWND(NULL, GetClipboardViewer());
12234
12235     /* Test registering hWnd1 as a viewer. */
12236     hRet = SetClipboardViewer(hWnd1);
12237     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12238     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12239     expect_HWND(NULL, hRet);
12240     expect_HWND(hWnd1, GetClipboardViewer());
12241
12242     /* Test that changing the clipboard actually refreshes the registered viewer. */
12243     clear_clipboard(hWnd1);
12244     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12245     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12246
12247     /* Again, but with different owner. */
12248     clear_clipboard(hWnd2);
12249     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12250     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12251
12252     /* Test re-registering same window. */
12253     hRet = SetClipboardViewer(hWnd1);
12254     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12255     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12256     expect_HWND(hWnd1, hRet);
12257     expect_HWND(hWnd1, GetClipboardViewer());
12258
12259     /* Test ChangeClipboardChain. */
12260     ChangeClipboardChain(hWnd2, hWnd3);
12261     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12262     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12263     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12264     expect_HWND(hWnd1, GetClipboardViewer());
12265
12266     ChangeClipboardChain(hWnd2, NULL);
12267     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12268     wm_change_cb_chain[0].lParam = 0;
12269     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12270     expect_HWND(hWnd1, GetClipboardViewer());
12271
12272     ChangeClipboardChain(NULL, hWnd2);
12273     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12274     expect_HWND(hWnd1, GetClipboardViewer());
12275
12276     /* Actually change clipboard viewer with ChangeClipboardChain. */
12277     ChangeClipboardChain(hWnd1, hWnd2);
12278     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12279     expect_HWND(hWnd2, GetClipboardViewer());
12280
12281     /* Test that no refresh messages are sent when viewer has unregistered. */
12282     clear_clipboard(hWnd2);
12283     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12284
12285     /* Register hWnd1 again. */
12286     ChangeClipboardChain(hWnd2, hWnd1);
12287     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12288     expect_HWND(hWnd1, GetClipboardViewer());
12289
12290     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12291      * changes the clipboard. When this happens, the system shouldn't send
12292      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12293      */
12294     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12295     clear_clipboard(hWnd2);
12296     /* The clipboard owner is changed in recursive_viewer_proc: */
12297     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
12298     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
12299
12300     /* Test unregistering. */
12301     ChangeClipboardChain(hWnd1, NULL);
12302     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
12303     expect_HWND(NULL, GetClipboardViewer());
12304
12305     clear_clipboard(hWnd1);
12306     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
12307
12308     DestroyWindow(hWnd1);
12309     DestroyWindow(hWnd2);
12310     DestroyWindow(hWnd3);
12311     SetClipboardViewer(hOrigViewer);
12312 }
12313
12314 static void test_PostMessage(void)
12315 {
12316     static const struct
12317     {
12318         HWND hwnd;
12319         BOOL ret;
12320     } data[] =
12321     {
12322         { HWND_TOP /* 0 */, TRUE },
12323         { HWND_BROADCAST, TRUE },
12324         { HWND_BOTTOM, TRUE },
12325         { HWND_TOPMOST, TRUE },
12326         { HWND_NOTOPMOST, FALSE },
12327         { HWND_MESSAGE, FALSE },
12328         { (HWND)0xdeadbeef, FALSE }
12329     };
12330     int i;
12331     HWND hwnd;
12332     BOOL ret;
12333     MSG msg;
12334     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
12335
12336     SetLastError(0xdeadbeef);
12337     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12338     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
12339     {
12340         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
12341         return;
12342     }
12343     assert(hwnd);
12344
12345     flush_events();
12346
12347     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
12348     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
12349
12350     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
12351     {
12352         memset(&msg, 0xab, sizeof(msg));
12353         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
12354         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
12355         if (data[i].ret)
12356         {
12357             if (data[i].hwnd)
12358                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
12359                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
12360                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
12361                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
12362             else
12363                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
12364                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
12365                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
12366                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
12367         }
12368     }
12369
12370     DestroyWindow(hwnd);
12371     flush_events();
12372 }
12373
12374 static const struct
12375 {
12376     DWORD exp, broken;
12377     BOOL todo;
12378 } wait_idle_expect[] =
12379 {
12380 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12381          { WAIT_TIMEOUT, 0,            FALSE },
12382          { WAIT_TIMEOUT, 0,            FALSE },
12383          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12384          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12385 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
12386          { WAIT_TIMEOUT, 0,            FALSE },
12387          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12388          { 0,            0,            FALSE },
12389          { 0,            0,            FALSE },
12390 /* 10 */ { 0,            0,            FALSE },
12391          { 0,            0,            FALSE },
12392          { 0,            WAIT_TIMEOUT, FALSE },
12393          { 0,            0,            FALSE },
12394          { 0,            0,            FALSE },
12395 /* 15 */ { 0,            0,            FALSE },
12396          { WAIT_TIMEOUT, 0,            FALSE },
12397          { WAIT_TIMEOUT, 0,            FALSE },
12398          { WAIT_TIMEOUT, 0,            FALSE },
12399          { WAIT_TIMEOUT, 0,            FALSE },
12400 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
12401 };
12402
12403 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
12404 {
12405     MSG msg;
12406
12407     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12408     Sleep( 200 );
12409     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12410     return 0;
12411 }
12412
12413 static void do_wait_idle_child( int arg )
12414 {
12415     WNDCLASS cls;
12416     MSG msg;
12417     HWND hwnd = 0;
12418     HANDLE thread;
12419     DWORD id;
12420     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
12421     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
12422
12423     memset( &cls, 0, sizeof(cls) );
12424     cls.lpfnWndProc   = DefWindowProc;
12425     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12426     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12427     cls.lpszClassName = "TestClass";
12428     RegisterClass( &cls );
12429
12430     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
12431
12432     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
12433     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
12434
12435     switch (arg)
12436     {
12437     case 0:
12438         SetEvent( start_event );
12439         break;
12440     case 1:
12441         SetEvent( start_event );
12442         Sleep( 200 );
12443         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12444         break;
12445     case 2:
12446         SetEvent( start_event );
12447         Sleep( 200 );
12448         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12449         PostThreadMessage( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
12450         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12451         break;
12452     case 3:
12453         SetEvent( start_event );
12454         Sleep( 200 );
12455         SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
12456         break;
12457     case 4:
12458         SetEvent( start_event );
12459         Sleep( 200 );
12460         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12461         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12462         break;
12463     case 5:
12464         SetEvent( start_event );
12465         Sleep( 200 );
12466         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12467         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12468         break;
12469     case 6:
12470         SetEvent( start_event );
12471         Sleep( 200 );
12472         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12473         while (PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ))
12474         {
12475             GetMessage( &msg, 0, 0, 0 );
12476             DispatchMessage( &msg );
12477         }
12478         break;
12479     case 7:
12480         SetEvent( start_event );
12481         Sleep( 200 );
12482         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12483         SetTimer( hwnd, 3, 1, NULL );
12484         Sleep( 200 );
12485         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12486         break;
12487     case 8:
12488         SetEvent( start_event );
12489         Sleep( 200 );
12490         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12491         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12492         break;
12493     case 9:
12494         SetEvent( start_event );
12495         Sleep( 200 );
12496         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12497         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12498         for (;;) GetMessage( &msg, 0, 0, 0 );
12499         break;
12500     case 10:
12501         SetEvent( start_event );
12502         Sleep( 200 );
12503         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12504         SetTimer( hwnd, 3, 1, NULL );
12505         Sleep( 200 );
12506         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12507         break;
12508     case 11:
12509         SetEvent( start_event );
12510         Sleep( 200 );
12511         return;  /* exiting the process makes WaitForInputIdle return success too */
12512     case 12:
12513         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12514         Sleep( 200 );
12515         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12516         SetEvent( start_event );
12517         break;
12518     case 13:
12519         SetEvent( start_event );
12520         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12521         Sleep( 200 );
12522         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
12523         WaitForSingleObject( thread, 10000 );
12524         CloseHandle( thread );
12525         break;
12526     case 14:
12527         SetEvent( start_event );
12528         Sleep( 200 );
12529         PeekMessage( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
12530         break;
12531     case 15:
12532         SetEvent( start_event );
12533         Sleep( 200 );
12534         PeekMessage( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
12535         break;
12536     case 16:
12537         SetEvent( start_event );
12538         Sleep( 200 );
12539         PeekMessage( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
12540         break;
12541     case 17:
12542         SetEvent( start_event );
12543         Sleep( 200 );
12544         PeekMessage( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
12545         break;
12546     case 18:
12547         SetEvent( start_event );
12548         Sleep( 200 );
12549         PeekMessage( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
12550         break;
12551     case 19:
12552         SetEvent( start_event );
12553         Sleep( 200 );
12554         PeekMessage( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
12555         break;
12556     case 20:
12557         SetEvent( start_event );
12558         Sleep( 200 );
12559         PeekMessage( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
12560         break;
12561     }
12562     WaitForSingleObject( end_event, 2000 );
12563     CloseHandle( start_event );
12564     CloseHandle( end_event );
12565     if (hwnd) DestroyWindow( hwnd );
12566 }
12567
12568 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
12569 {
12570     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
12571     return DefWindowProcA( hwnd, msg, wp, lp );
12572 }
12573
12574 static DWORD CALLBACK wait_idle_thread( void *arg )
12575 {
12576     WNDCLASS cls;
12577     MSG msg;
12578     HWND hwnd;
12579
12580     memset( &cls, 0, sizeof(cls) );
12581     cls.lpfnWndProc   = wait_idle_proc;
12582     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12583     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12584     cls.lpszClassName = "TestClass";
12585     RegisterClass( &cls );
12586
12587     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
12588     while (GetMessage( &msg, 0, 0, 0 )) DispatchMessage( &msg );
12589     DestroyWindow(hwnd);
12590     return 0;
12591 }
12592
12593 static void test_WaitForInputIdle( char *argv0 )
12594 {
12595     char path[MAX_PATH];
12596     PROCESS_INFORMATION pi;
12597     STARTUPINFOA startup;
12598     BOOL ret;
12599     HANDLE start_event, end_event, thread;
12600     unsigned int i;
12601     DWORD id;
12602     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
12603     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
12604     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
12605
12606     if (console_app)  /* build the test with -mwindows for better coverage */
12607         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
12608
12609     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
12610     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
12611     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
12612     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
12613
12614     memset( &startup, 0, sizeof(startup) );
12615     startup.cb = sizeof(startup);
12616     startup.dwFlags = STARTF_USESHOWWINDOW;
12617     startup.wShowWindow = SW_SHOWNORMAL;
12618
12619     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
12620
12621     for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
12622     {
12623         ResetEvent( start_event );
12624         ResetEvent( end_event );
12625         sprintf( path, "%s msg %u", argv0, i );
12626         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
12627         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
12628         if (ret)
12629         {
12630             ret = WaitForSingleObject( start_event, 5000 );
12631             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
12632             if (ret == WAIT_OBJECT_0)
12633             {
12634                 ret = WaitForInputIdle( pi.hProcess, 1000 );
12635                 if (ret == WAIT_FAILED)
12636                     ok( console_app ||
12637                         ret == wait_idle_expect[i].exp ||
12638                         broken(ret == wait_idle_expect[i].broken),
12639                         "%u: WaitForInputIdle error %08x expected %08x\n",
12640                         i, ret, wait_idle_expect[i].exp );
12641                 else if (wait_idle_expect[i].todo)
12642                     todo_wine
12643                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12644                         "%u: WaitForInputIdle error %08x expected %08x\n",
12645                         i, ret, wait_idle_expect[i].exp );
12646                 else
12647                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12648                         "%u: WaitForInputIdle error %08x expected %08x\n",
12649                         i, ret, wait_idle_expect[i].exp );
12650                 SetEvent( end_event );
12651                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
12652             }
12653             TerminateProcess( pi.hProcess, 0 );  /* just in case */
12654             winetest_wait_child_process( pi.hProcess );
12655             ret = WaitForInputIdle( pi.hProcess, 100 );
12656             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
12657             CloseHandle( pi.hProcess );
12658             CloseHandle( pi.hThread );
12659         }
12660     }
12661     CloseHandle( start_event );
12662     PostThreadMessage( id, WM_QUIT, 0, 0 );
12663     WaitForSingleObject( thread, 10000 );
12664     CloseHandle( thread );
12665 }
12666
12667 static const struct message WmSetParentSeq_1[] = {
12668     { WM_SHOWWINDOW, sent|wparam, 0 },
12669     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12670     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12671     { WM_CHILDACTIVATE, sent },
12672     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
12673     { WM_MOVE, sent|defwinproc|wparam, 0 },
12674     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12675     { WM_SHOWWINDOW, sent|wparam, 1 },
12676     { 0 }
12677 };
12678
12679 static const struct message WmSetParentSeq_2[] = {
12680     { WM_SHOWWINDOW, sent|wparam, 0 },
12681     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12682     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
12683     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12684     { WM_NCACTIVATE, sent|wparam, 0 },
12685     { WM_ACTIVATE, sent|wparam, 0 },
12686     { WM_ACTIVATEAPP, sent|wparam, 0 },
12687     { WM_KILLFOCUS, sent|wparam, 0 },
12688     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12689     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12690     { HCBT_ACTIVATE, hook },
12691     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
12692     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
12693     { WM_NCACTIVATE, sent|wparam, 1 },
12694     { WM_ACTIVATE, sent|wparam, 1 },
12695     { HCBT_SETFOCUS, hook },
12696     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12697     { WM_SETFOCUS, sent|defwinproc },
12698     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
12699     { WM_MOVE, sent|defwinproc|wparam, 0 },
12700     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12701     { WM_SHOWWINDOW, sent|wparam, 1 },
12702     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12703     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
12704     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12705     { 0 }
12706 };
12707
12708
12709 static void test_SetParent(void)
12710 {
12711     HWND parent1, parent2, child, popup;
12712     RECT rc, rc_old;
12713
12714     parent1 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
12715                             100, 100, 200, 200, 0, 0, 0, NULL);
12716     ok(parent1 != 0, "Failed to create parent1 window\n");
12717
12718     parent2 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
12719                             400, 100, 200, 200, 0, 0, 0, NULL);
12720     ok(parent2 != 0, "Failed to create parent2 window\n");
12721
12722     /* WS_CHILD window */
12723     child = CreateWindowEx(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
12724                            10, 10, 150, 150, parent1, 0, 0, NULL);
12725     ok(child != 0, "Failed to create child window\n");
12726
12727     GetWindowRect(parent1, &rc);
12728     trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12729     GetWindowRect(child, &rc_old);
12730     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
12731     trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
12732
12733     flush_sequence();
12734
12735     SetParent(child, parent2);
12736     flush_events();
12737     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
12738
12739     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
12740     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
12741
12742     GetWindowRect(parent2, &rc);
12743     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12744     GetWindowRect(child, &rc);
12745     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
12746     trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12747
12748     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
12749        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
12750        rc.left, rc.top, rc.right, rc.bottom );
12751
12752     /* WS_POPUP window */
12753     popup = CreateWindowEx(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
12754                            20, 20, 100, 100, 0, 0, 0, NULL);
12755     ok(popup != 0, "Failed to create popup window\n");
12756
12757     GetWindowRect(popup, &rc_old);
12758     trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
12759
12760     flush_sequence();
12761
12762     SetParent(popup, child);
12763     flush_events();
12764     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
12765
12766     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
12767     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
12768
12769     GetWindowRect(child, &rc);
12770     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12771     GetWindowRect(popup, &rc);
12772     MapWindowPoints(0, child, (POINT *)&rc, 2);
12773     trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12774
12775     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
12776        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
12777        rc.left, rc.top, rc.right, rc.bottom );
12778
12779     DestroyWindow(popup);
12780     DestroyWindow(child);
12781     DestroyWindow(parent1);
12782     DestroyWindow(parent2);
12783
12784     flush_sequence();
12785 }
12786
12787 START_TEST(msg)
12788 {
12789     char **test_argv;
12790     BOOL ret;
12791     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
12792     HMODULE hModuleImm32;
12793     BOOL (WINAPI *pImmDisableIME)(DWORD);
12794
12795     int argc = winetest_get_mainargs( &test_argv );
12796     if (argc >= 3)
12797     {
12798         unsigned int arg;
12799         /* Child process. */
12800         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
12801         do_wait_idle_child( arg );
12802         return;
12803     }
12804
12805     init_procs();
12806
12807     hModuleImm32 = LoadLibrary("imm32.dll");
12808     if (hModuleImm32) {
12809         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
12810         if (pImmDisableIME)
12811             pImmDisableIME(0);
12812     }
12813     pImmDisableIME = NULL;
12814     FreeLibrary(hModuleImm32);
12815
12816     if (!RegisterWindowClasses()) assert(0);
12817
12818     if (pSetWinEventHook)
12819     {
12820         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
12821                                        GetModuleHandleA(0), win_event_proc,
12822                                        0, GetCurrentThreadId(),
12823                                        WINEVENT_INCONTEXT);
12824         if (pIsWinEventHookInstalled && hEvent_hook)
12825         {
12826             UINT event;
12827             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
12828                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
12829         }
12830     }
12831     if (!hEvent_hook) win_skip( "no win event hook support\n" );
12832
12833     cbt_hook_thread_id = GetCurrentThreadId();
12834     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
12835     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
12836
12837     test_winevents();
12838
12839     /* Fix message sequences before removing 4 lines below */
12840 #if 1
12841     if (pUnhookWinEvent && hEvent_hook)
12842     {
12843         ret = pUnhookWinEvent(hEvent_hook);
12844         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
12845         pUnhookWinEvent = 0;
12846     }
12847     hEvent_hook = 0;
12848 #endif
12849
12850     test_SetParent();
12851     test_PostMessage();
12852     test_ShowWindow();
12853     test_PeekMessage();
12854     test_PeekMessage2();
12855     test_WaitForInputIdle( test_argv[0] );
12856     test_scrollwindowex();
12857     test_messages();
12858     test_setwindowpos();
12859     test_showwindow();
12860     invisible_parent_tests();
12861     test_mdi_messages();
12862     test_button_messages();
12863     test_static_messages();
12864     test_listbox_messages();
12865     test_combobox_messages();
12866     test_wmime_keydown_message();
12867     test_paint_messages();
12868     test_interthread_messages();
12869     test_message_conversion();
12870     test_accelerators();
12871     test_timers();
12872     test_timers_no_wnd();
12873     if (hCBT_hook) test_set_hook();
12874     test_DestroyWindow();
12875     test_DispatchMessage();
12876     test_SendMessageTimeout();
12877     test_edit_messages();
12878     test_quit_message();
12879     test_SetActiveWindow();
12880
12881     if (!pTrackMouseEvent)
12882         win_skip("TrackMouseEvent is not available\n");
12883     else
12884         test_TrackMouseEvent();
12885
12886     test_SetWindowRgn();
12887     test_sys_menu();
12888     test_dialog_messages();
12889     test_nullCallback();
12890     test_dbcs_wm_char();
12891     test_menu_messages();
12892     test_paintingloop();
12893     test_defwinproc();
12894     test_clipboard_viewers();
12895     /* keep it the last test, under Windows it tends to break the tests
12896      * which rely on active/foreground windows being correct.
12897      */
12898     test_SetForegroundWindow();
12899
12900     UnhookWindowsHookEx(hCBT_hook);
12901     if (pUnhookWinEvent && hEvent_hook)
12902     {
12903         ret = pUnhookWinEvent(hEvent_hook);
12904         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
12905         SetLastError(0xdeadbeef);
12906         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
12907         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
12908            GetLastError() == 0xdeadbeef, /* Win9x */
12909            "unexpected error %d\n", GetLastError());
12910     }
12911 }