dinput: BuildActionMap and SetActionMap stubs for generic joystick.
[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 hKBD_hook;
83 static HHOOK hCBT_hook;
84 static DWORD cbt_hook_thread_id;
85
86 static const WCHAR testWindowClassW[] =
87 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
88
89 /*
90 FIXME: add tests for these
91 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
92  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
93  WS_THICKFRAME: thick border
94  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
95  WS_BORDER (default for overlapped windows): single black border
96  none (default for child (and popup?) windows): no border
97 */
98
99 typedef enum {
100     sent=0x1,
101     posted=0x2,
102     parent=0x4,
103     wparam=0x8,
104     lparam=0x10,
105     defwinproc=0x20,
106     beginpaint=0x40,
107     optional=0x80,
108     hook=0x100,
109     winevent_hook=0x200,
110     kbd_hook=0x400
111 } msg_flags_t;
112
113 struct message {
114     UINT message;          /* the WM_* code */
115     msg_flags_t flags;     /* message props */
116     WPARAM wParam;         /* expected value of wParam */
117     LPARAM lParam;         /* expected value of lParam */
118     WPARAM wp_mask;        /* mask for wParam checks */
119     LPARAM lp_mask;        /* mask for lParam checks */
120 };
121
122 struct recvd_message {
123     UINT message;          /* the WM_* code */
124     msg_flags_t flags;     /* message props */
125     HWND hwnd;             /* window that received the message */
126     WPARAM wParam;         /* expected value of wParam */
127     LPARAM lParam;         /* expected value of lParam */
128     int line;              /* source line where logged */
129     const char *descr;     /* description for trace output */
130     char output[512];      /* trace output */
131 };
132
133 /* Empty message sequence */
134 static const struct message WmEmptySeq[] =
135 {
136     { 0 }
137 };
138 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
139 static const struct message WmCreateOverlappedSeq[] = {
140     { HCBT_CREATEWND, hook },
141     { WM_GETMINMAXINFO, sent },
142     { WM_NCCREATE, sent },
143     { WM_NCCALCSIZE, sent|wparam, 0 },
144     { 0x0093, sent|defwinproc|optional },
145     { 0x0094, sent|defwinproc|optional },
146     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
147     { WM_CREATE, sent },
148     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
149     { 0 }
150 };
151 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
152  * for a not visible overlapped window.
153  */
154 static const struct message WmSWP_ShowOverlappedSeq[] = {
155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
156     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
157     { WM_NCPAINT, sent|wparam|optional, 1 },
158     { WM_GETTEXT, sent|defwinproc|optional },
159     { WM_ERASEBKGND, sent|optional },
160     { HCBT_ACTIVATE, hook },
161     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
162     { WM_NOTIFYFORMAT, sent|optional },
163     { WM_QUERYUISTATE, sent|optional },
164     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
165     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
166     { WM_ACTIVATEAPP, sent|wparam, 1 },
167     { WM_NCACTIVATE, sent },
168     { WM_GETTEXT, sent|defwinproc|optional },
169     { WM_ACTIVATE, sent|wparam, 1 },
170     { HCBT_SETFOCUS, hook },
171     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
172     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
173     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
174     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
175     { WM_GETTEXT, sent|optional },
176     { WM_NCPAINT, sent|wparam|optional, 1 },
177     { WM_GETTEXT, sent|defwinproc|optional },
178     { WM_ERASEBKGND, sent|optional },
179     /* Win9x adds SWP_NOZORDER below */
180     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
181     { WM_GETTEXT, sent|optional },
182     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
183     { WM_NCPAINT, sent|wparam|optional, 1 },
184     { WM_ERASEBKGND, sent|optional },
185     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
186     { WM_SYNCPAINT, sent|optional },
187     { WM_GETTITLEBARINFOEX, sent|optional },
188     { WM_PAINT, sent|optional },
189     { WM_NCPAINT, sent|beginpaint|optional },
190     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
191     { WM_ERASEBKGND, sent|beginpaint|optional },
192     { 0 }
193 };
194 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
195  * for a visible overlapped window.
196  */
197 static const struct message WmSWP_HideOverlappedSeq[] = {
198     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
199     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
200     { HCBT_ACTIVATE, hook|optional },
201     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
202     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
203     { WM_NCACTIVATE, sent|optional },
204     { WM_ACTIVATE, sent|optional },
205     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
206     { 0 }
207 };
208
209 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
210  * for a visible overlapped window.
211  */
212 static const struct message WmSWP_ResizeSeq[] = {
213     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
214     { WM_GETMINMAXINFO, sent|defwinproc },
215     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
216     { WM_NCPAINT, sent|optional },
217     { WM_GETTEXT, sent|defwinproc|optional },
218     { WM_ERASEBKGND, sent|optional },
219     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
220     { WM_SIZE, sent|defwinproc|optional },
221     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
222     { WM_NCPAINT, sent|optional },
223     { WM_GETTEXT, sent|defwinproc|optional },
224     { WM_ERASEBKGND, sent|optional },
225     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
226     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
227     { 0 }
228 };
229
230 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
231  * for a visible popup window.
232  */
233 static const struct message WmSWP_ResizePopupSeq[] = {
234     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
235     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
236     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
237     { WM_NCPAINT, sent|optional },
238     { WM_GETTEXT, sent|defwinproc|optional },
239     { WM_ERASEBKGND, sent|optional },
240     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
241     { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
242     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
243     { WM_NCPAINT, sent|optional },
244     { WM_GETTEXT, sent|defwinproc|optional },
245     { WM_ERASEBKGND, sent|optional },
246     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
247     { 0 }
248 };
249
250 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
251  * for a visible overlapped window.
252  */
253 static const struct message WmSWP_MoveSeq[] = {
254     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
255     { WM_NCPAINT, sent|optional },
256     { WM_GETTEXT, sent|defwinproc|optional },
257     { WM_ERASEBKGND, sent|optional },
258     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
259     { WM_MOVE, sent|defwinproc|wparam, 0 },
260     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
261     { 0 }
262 };
263 /* Resize with SetWindowPos(SWP_NOZORDER)
264  * for a visible overlapped window
265  * SWP_NOZORDER is stripped by the logging code
266  */
267 static const struct message WmSWP_ResizeNoZOrder[] = {
268     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
269     { WM_GETMINMAXINFO, sent|defwinproc },
270     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
271     { WM_NCPAINT, sent|optional },
272     { WM_GETTEXT, sent|defwinproc|optional },
273     { WM_ERASEBKGND, sent|optional },
274     { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
275       SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
276     { WM_MOVE, sent|defwinproc|optional },
277     { WM_SIZE, sent|defwinproc|optional },
278     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
279     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
280     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
281     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
282     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
283     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
284     { 0 }
285 };
286
287 /* Switch visible mdi children */
288 static const struct message WmSwitchChild[] = {
289     /* Switch MDI child */
290     { WM_MDIACTIVATE, sent },/* in the MDI client */
291     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
292     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
293     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
294     /* Deactivate 2nd MDI child */
295     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
296     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
297     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
298     /* Preparing for maximize and maximaze the 1st MDI child */
299     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
300     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
301     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
302     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
303     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
304     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
305     /* Lock redraw 2nd MDI child */
306     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
307     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
308     /* Restore 2nd MDI child */
309     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
310     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
311     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
312     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
313     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
314     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
315     /* Redraw 2nd MDI child */
316     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
317     /* Redraw MDI frame */
318     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
319     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
320     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
321     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
322     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
323     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
324     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
325     { HCBT_SETFOCUS, hook },
326     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
327     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
328     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
329     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
330     { WM_SETFOCUS, sent },/* in the MDI client */
331     { HCBT_SETFOCUS, hook },
332     { WM_KILLFOCUS, sent },/* in the MDI client */
333     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
334     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
335     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
336     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
337     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
338     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
339     { 0 }
340 };
341
342 /* Switch visible not maximized mdi children */
343 static const struct message WmSwitchNotMaximizedChild[] = {
344     /* Switch not maximized MDI child */
345     { WM_MDIACTIVATE, sent },/* in the MDI client */
346     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
347     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
348     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
349     /* Deactivate 1st MDI child */
350     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
351     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
352     /* Activate 2nd MDI child */
353     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
354     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
355     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
356     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
357     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
358     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
359     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
360     { HCBT_SETFOCUS, hook },
361     { WM_KILLFOCUS, sent }, /* in the  MDI client */
362     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
363     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
364     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
365     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
366     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
367     { 0 }
368 };
369
370
371 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
372                 SWP_NOZORDER|SWP_FRAMECHANGED)
373  * for a visible overlapped window with WS_CLIPCHILDREN style set.
374  */
375 static const struct message WmSWP_FrameChanged_clip[] = {
376     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
377     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
378     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
379     { WM_GETTEXT, sent|parent|defwinproc|optional },
380     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
381     { WM_NCPAINT, sent }, /* wparam != 1 */
382     { WM_ERASEBKGND, sent },
383     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
384     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
385     { WM_PAINT, sent },
386     { 0 }
387 };
388 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
389                 SWP_NOZORDER|SWP_FRAMECHANGED)
390  * for a visible overlapped window.
391  */
392 static const struct message WmSWP_FrameChangedDeferErase[] = {
393     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
394     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
395     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
396     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
397     { WM_PAINT, sent|parent|optional },
398     { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
399     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
400     { WM_PAINT, sent },
401     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
402     { WM_ERASEBKGND, sent|beginpaint|optional },
403     { 0 }
404 };
405
406 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
407                 SWP_NOZORDER|SWP_FRAMECHANGED)
408  * for a visible overlapped window without WS_CLIPCHILDREN style set.
409  */
410 static const struct message WmSWP_FrameChanged_noclip[] = {
411     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
412     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
413     { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
414     { WM_GETTEXT, sent|parent|defwinproc|optional },
415     { WM_ERASEBKGND, sent|parent|optional },
416     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
417     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
418     { WM_PAINT, sent },
419     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
420     { WM_ERASEBKGND, sent|beginpaint|optional },
421     { 0 }
422 };
423
424 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
425 static const struct message WmShowOverlappedSeq[] = {
426     { WM_SHOWWINDOW, sent|wparam, 1 },
427     { WM_NCPAINT, sent|wparam|optional, 1 },
428     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
429     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
430     { WM_NCPAINT, sent|wparam|optional, 1 },
431     { WM_GETTEXT, sent|defwinproc|optional },
432     { WM_ERASEBKGND, sent|optional },
433     { HCBT_ACTIVATE, hook },
434     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
435     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
436     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
437     { WM_NCPAINT, sent|wparam|optional, 1 },
438     { WM_ACTIVATEAPP, sent|wparam, 1 },
439     { WM_NCACTIVATE, sent|wparam, 1 },
440     { WM_GETTEXT, sent|defwinproc|optional },
441     { WM_ACTIVATE, sent|wparam, 1 },
442     { HCBT_SETFOCUS, hook },
443     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
444     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
445     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
446     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
447     { WM_GETTEXT, sent|optional },
448     { WM_NCPAINT, sent|wparam|optional, 1 },
449     { WM_GETTEXT, sent|defwinproc|optional },
450     { WM_ERASEBKGND, sent|optional },
451     /* Win9x adds SWP_NOZORDER below */
452     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
453     { WM_NCCALCSIZE, sent|optional },
454     { WM_GETTEXT, sent|optional },
455     { WM_NCPAINT, sent|optional },
456     { WM_ERASEBKGND, sent|optional },
457     { WM_SYNCPAINT, sent|optional },
458 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
459        * messages. Does that mean that CreateWindow doesn't set initial
460        * window dimensions for overlapped windows?
461        */
462     { WM_SIZE, sent },
463     { WM_MOVE, sent },
464 #endif
465     { WM_PAINT, sent|optional },
466     { WM_NCPAINT, sent|beginpaint|optional },
467     { 0 }
468 };
469 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
470 static const struct message WmShowMaxOverlappedSeq[] = {
471     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
472     { WM_GETMINMAXINFO, sent },
473     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
474     { WM_GETMINMAXINFO, sent|defwinproc },
475     { WM_NCCALCSIZE, sent|wparam, TRUE },
476     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
477     { HCBT_ACTIVATE, hook },
478     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
479     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
480     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
481     { WM_ACTIVATEAPP, sent|wparam, 1 },
482     { WM_NCACTIVATE, sent|wparam, 1 },
483     { WM_GETTEXT, sent|defwinproc|optional },
484     { WM_ACTIVATE, sent|wparam, 1 },
485     { HCBT_SETFOCUS, hook },
486     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
487     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
488     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
489     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
490     { WM_GETTEXT, sent|optional },
491     { WM_NCPAINT, sent|wparam|optional, 1 },
492     { WM_GETTEXT, sent|defwinproc|optional },
493     { WM_ERASEBKGND, sent|optional },
494     /* Win9x adds SWP_NOZORDER below */
495     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
496     { WM_MOVE, sent|defwinproc },
497     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
498     { WM_GETTEXT, sent|optional },
499     { WM_NCCALCSIZE, sent|optional },
500     { WM_NCPAINT, sent|optional },
501     { WM_ERASEBKGND, sent|optional },
502     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
503     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
504     { WM_SYNCPAINT, sent|optional },
505     { WM_GETTITLEBARINFOEX, sent|optional },
506     { WM_PAINT, sent|optional },
507     { WM_NCPAINT, sent|beginpaint|optional },
508     { WM_ERASEBKGND, sent|beginpaint|optional },
509     { 0 }
510 };
511 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
512 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
513     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
514     { WM_GETTEXT, sent|optional },
515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
516     { WM_GETMINMAXINFO, sent|defwinproc },
517     { WM_NCCALCSIZE, sent|wparam, TRUE },
518     { WM_NCPAINT, sent|optional },
519     { WM_GETTEXT, sent|defwinproc|optional },
520     { WM_ERASEBKGND, sent|optional },
521     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
522     { WM_MOVE, sent|defwinproc|optional },
523     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
524     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
525     { WM_NCPAINT, sent|optional },
526     { WM_ERASEBKGND, sent|optional },
527     { WM_PAINT, sent|optional },
528     { WM_GETTITLEBARINFOEX, sent|optional },
529     { WM_NCPAINT, sent|beginpaint|optional },
530     { WM_ERASEBKGND, sent|beginpaint|optional },
531     { 0 }
532 };
533 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
534 static const struct message WmShowRestoreMinOverlappedSeq[] = {
535     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
536     { WM_QUERYOPEN, sent|optional },
537     { WM_GETTEXT, sent|optional },
538     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
539     { WM_GETMINMAXINFO, sent|defwinproc },
540     { WM_NCCALCSIZE, sent|wparam, TRUE },
541     { HCBT_ACTIVATE, hook },
542     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
543     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
544     { WM_ACTIVATEAPP, sent|wparam, 1 },
545     { WM_NCACTIVATE, sent|wparam, 1 },
546     { WM_GETTEXT, sent|defwinproc|optional },
547     { WM_ACTIVATE, sent|wparam, 1 },
548     { HCBT_SETFOCUS, hook },
549     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
550     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
551     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
552     { WM_GETTEXT, sent|optional },
553     { WM_NCPAINT, sent|wparam|optional, 1 },
554     { WM_GETTEXT, sent|defwinproc|optional },
555     { WM_ERASEBKGND, sent },
556     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
557     { WM_MOVE, sent|defwinproc },
558     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
559     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
560     { WM_NCPAINT, sent|wparam|optional, 1 },
561     { WM_ERASEBKGND, sent|optional },
562     { WM_ACTIVATE, sent|wparam, 1 },
563     { WM_GETTEXT, sent|optional },
564     { WM_PAINT, sent|optional },
565     { WM_GETTITLEBARINFOEX, sent|optional },
566     { WM_NCPAINT, sent|beginpaint|optional },
567     { WM_ERASEBKGND, sent|beginpaint|optional },
568     { 0 }
569 };
570 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
571 static const struct message WmShowMinOverlappedSeq[] = {
572     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
573     { HCBT_SETFOCUS, hook },
574     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
575     { WM_KILLFOCUS, sent },
576     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
577     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
578     { WM_GETTEXT, sent|optional },
579     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
580     { WM_GETMINMAXINFO, sent|defwinproc },
581     { WM_NCCALCSIZE, sent|wparam, TRUE },
582     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
583     { WM_NCPAINT, sent|optional },
584     { WM_GETTEXT, sent|defwinproc|optional },
585     { WM_WINDOWPOSCHANGED, sent },
586     { WM_MOVE, sent|defwinproc },
587     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
588     { WM_NCCALCSIZE, sent|optional },
589     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
590     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
591     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
592     { WM_NCACTIVATE, sent|wparam, 0 },
593     { WM_GETTEXT, sent|defwinproc|optional },
594     { WM_ACTIVATE, sent },
595     { WM_ACTIVATEAPP, sent|wparam, 0 },
596
597     /* Vista sometimes restores the window right away... */
598     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
599     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
600     { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
601     { WM_QUERYOPEN, sent|optional },
602     { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
603     { WM_GETMINMAXINFO, sent|optional|defwinproc },
604     { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
605     { HCBT_ACTIVATE, hook|optional },
606     { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
607     { WM_NCACTIVATE, sent|optional },
608     { WM_GETTEXT, sent|optional },
609     { WM_ACTIVATE, sent|optional|wparam, 1 },
610     { HCBT_SETFOCUS, hook|optional },
611     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
612     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
613     { WM_SETFOCUS, sent|optional },
614     { WM_NCPAINT, sent|optional },
615     { WM_GETTEXT, sent|defwinproc|optional },
616     { WM_ERASEBKGND, sent|optional },
617     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
618     { WM_MOVE, sent|defwinproc|optional },
619     { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
620     { WM_ACTIVATE, sent|optional|wparam, 1 },
621     { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
622     { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
623
624     { WM_PAINT, sent|optional },
625     { WM_NCPAINT, sent|beginpaint|optional },
626     { WM_ERASEBKGND, sent|beginpaint|optional },
627     { 0 }
628 };
629 /* ShowWindow(SW_HIDE) for a visible overlapped window */
630 static const struct message WmHideOverlappedSeq[] = {
631     { WM_SHOWWINDOW, sent|wparam, 0 },
632     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
633     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
634     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
635     { WM_SIZE, sent|optional }, /* XP doesn't send it */
636     { WM_MOVE, sent|optional }, /* XP doesn't send it */
637     { WM_NCACTIVATE, sent|wparam|optional, 0 },
638     { WM_ACTIVATE, sent|wparam|optional, 0 },
639     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
640     { HCBT_SETFOCUS, hook|optional },
641     { WM_KILLFOCUS, sent|wparam, 0 },
642     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
643     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
644     { 0 }
645 };
646 /* DestroyWindow for a visible overlapped window */
647 static const struct message WmDestroyOverlappedSeq[] = {
648     { HCBT_DESTROYWND, hook },
649     { 0x0090, sent|optional },
650     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
651     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
652     { 0x0090, sent|optional },
653     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
654     { WM_NCACTIVATE, sent|optional|wparam, 0 },
655     { WM_ACTIVATE, sent|optional },
656     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
657     { WM_KILLFOCUS, sent|optional|wparam, 0 },
658     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
659     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
660     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
661     { WM_DESTROY, sent },
662     { WM_NCDESTROY, sent },
663     { 0 }
664 };
665 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
666 static const struct message WmCreateMaxPopupSeq[] = {
667     { HCBT_CREATEWND, hook },
668     { WM_NCCREATE, sent },
669     { WM_NCCALCSIZE, sent|wparam, 0 },
670     { WM_CREATE, sent },
671     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
672     { WM_SIZE, sent|wparam, SIZE_RESTORED },
673     { WM_MOVE, sent },
674     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
675     { WM_GETMINMAXINFO, sent },
676     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
677     { WM_NCCALCSIZE, sent|wparam, TRUE },
678     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
679     { WM_MOVE, sent|defwinproc },
680     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
681     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
682     { WM_SHOWWINDOW, sent|wparam, 1 },
683     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
684     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
685     { HCBT_ACTIVATE, hook },
686     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
687     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
688     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
689     { WM_NCPAINT, sent|wparam|optional, 1 },
690     { WM_ERASEBKGND, sent|optional },
691     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
692     { WM_ACTIVATEAPP, sent|wparam, 1 },
693     { WM_NCACTIVATE, sent },
694     { WM_ACTIVATE, sent|wparam, 1 },
695     { HCBT_SETFOCUS, hook },
696     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
697     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
698     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
699     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
700     { WM_GETTEXT, sent|optional },
701     { WM_SYNCPAINT, sent|wparam|optional, 4 },
702     { WM_NCPAINT, sent|wparam|optional, 1 },
703     { WM_ERASEBKGND, sent|optional },
704     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
705     { WM_ERASEBKGND, sent|defwinproc|optional },
706     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
707     { 0 }
708 };
709 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
710 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
711     { HCBT_CREATEWND, hook },
712     { WM_NCCREATE, sent },
713     { WM_NCCALCSIZE, sent|wparam, 0 },
714     { WM_CREATE, sent },
715     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
716     { WM_SIZE, sent|wparam, SIZE_RESTORED },
717     { WM_MOVE, sent },
718     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
719     { WM_GETMINMAXINFO, sent },
720     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
721     { WM_NCCALCSIZE, sent|wparam, TRUE },
722     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
723     { WM_MOVE, sent|defwinproc },
724     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
725     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
726     { 0 }
727 };
728 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
729 static const struct message WmShowMaxPopupResizedSeq[] = {
730     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
731     { WM_GETMINMAXINFO, sent },
732     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
733     { WM_NCCALCSIZE, sent|wparam, TRUE },
734     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
735     { HCBT_ACTIVATE, hook },
736     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
737     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
738     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
739     { WM_NCPAINT, sent|wparam|optional, 1 },
740     { WM_ERASEBKGND, sent|optional },
741     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
742     { WM_ACTIVATEAPP, sent|wparam, 1 },
743     { WM_NCACTIVATE, sent },
744     { WM_ACTIVATE, sent|wparam, 1 },
745     { HCBT_SETFOCUS, hook },
746     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
747     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
748     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
749     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
750     { WM_GETTEXT, sent|optional },
751     { WM_NCPAINT, sent|wparam|optional, 1 },
752     { WM_ERASEBKGND, sent|optional },
753     { WM_WINDOWPOSCHANGED, sent },
754     /* WinNT4.0 sends WM_MOVE */
755     { WM_MOVE, sent|defwinproc|optional },
756     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
757     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
758     { 0 }
759 };
760 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
761 static const struct message WmShowMaxPopupSeq[] = {
762     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
763     { WM_GETMINMAXINFO, sent },
764     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
765     { WM_NCCALCSIZE, sent|wparam, TRUE },
766     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
767     { HCBT_ACTIVATE, hook },
768     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
769     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
770     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
771     { WM_ACTIVATEAPP, sent|wparam, 1 },
772     { WM_NCACTIVATE, sent },
773     { WM_ACTIVATE, sent|wparam, 1 },
774     { HCBT_SETFOCUS, hook },
775     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
776     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
777     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
778     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
779     { WM_GETTEXT, sent|optional },
780     { WM_SYNCPAINT, sent|wparam|optional, 4 },
781     { WM_NCPAINT, sent|wparam|optional, 1 },
782     { WM_ERASEBKGND, sent|optional },
783     { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
784     { WM_ERASEBKGND, sent|defwinproc|optional },
785     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
786     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
787     { 0 }
788 };
789 /* CreateWindow(WS_VISIBLE) for popup window */
790 static const struct message WmCreatePopupSeq[] = {
791     { HCBT_CREATEWND, hook },
792     { WM_NCCREATE, sent },
793     { WM_NCCALCSIZE, sent|wparam, 0 },
794     { WM_CREATE, sent },
795     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
796     { WM_SIZE, sent|wparam, SIZE_RESTORED },
797     { WM_MOVE, sent },
798     { WM_SHOWWINDOW, sent|wparam, 1 },
799     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
800     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
801     { HCBT_ACTIVATE, hook },
802     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
803     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
804     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
805     { WM_NCPAINT, sent|wparam|optional, 1 },
806     { WM_ERASEBKGND, sent|optional },
807     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
808     { WM_ACTIVATEAPP, sent|wparam, 1 },
809     { WM_NCACTIVATE, sent },
810     { WM_ACTIVATE, sent|wparam, 1 },
811     { HCBT_SETFOCUS, hook },
812     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
813     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
814     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
815     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
816     { WM_GETTEXT, sent|optional },
817     { WM_SYNCPAINT, sent|wparam|optional, 4 },
818     { WM_NCPAINT, sent|wparam|optional, 1 },
819     { WM_ERASEBKGND, sent|optional },
820     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
821     { 0 }
822 };
823 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
824 static const struct message WmShowVisMaxPopupSeq[] = {
825     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
826     { WM_GETMINMAXINFO, sent },
827     { WM_GETTEXT, sent|optional },
828     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
829     { WM_GETTEXT, sent|optional },
830     { WM_NCCALCSIZE, sent|wparam, TRUE },
831     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
832     { WM_NCPAINT, sent|wparam|optional, 1 },
833     { WM_ERASEBKGND, sent|optional },
834     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
835     { WM_MOVE, sent|defwinproc },
836     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
837     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
838     { 0 }
839 };
840 /* CreateWindow (for a child popup window, not initially visible) */
841 static const struct message WmCreateChildPopupSeq[] = {
842     { HCBT_CREATEWND, hook },
843     { WM_NCCREATE, sent }, 
844     { WM_NCCALCSIZE, sent|wparam, 0 },
845     { WM_CREATE, sent },
846     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
847     { WM_SIZE, sent|wparam, SIZE_RESTORED },
848     { WM_MOVE, sent },
849     { 0 }
850 };
851 /* CreateWindow (for a popup window, not initially visible,
852  * which sets WS_VISIBLE in WM_CREATE handler)
853  */
854 static const struct message WmCreateInvisiblePopupSeq[] = {
855     { HCBT_CREATEWND, hook },
856     { WM_NCCREATE, sent }, 
857     { WM_NCCALCSIZE, sent|wparam, 0 },
858     { WM_CREATE, sent },
859     { WM_STYLECHANGING, sent },
860     { WM_STYLECHANGED, sent },
861     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
862     { WM_SIZE, sent|wparam, SIZE_RESTORED },
863     { WM_MOVE, sent },
864     { 0 }
865 };
866 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
867  * for a popup window with WS_VISIBLE style set
868  */
869 static const struct message WmShowVisiblePopupSeq_2[] = {
870     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
871     { 0 }
872 };
873 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
874  * for a popup window with WS_VISIBLE style set
875  */
876 static const struct message WmShowVisiblePopupSeq_3[] = {
877     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
878     { HCBT_ACTIVATE, hook },
879     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
880     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
881     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
882     { WM_NCACTIVATE, sent },
883     { WM_ACTIVATE, sent|wparam, 1 },
884     { HCBT_SETFOCUS, hook },
885     { WM_KILLFOCUS, sent|parent },
886     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
887     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
888     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
889     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
890     { WM_SETFOCUS, sent|defwinproc },
891     { WM_GETTEXT, sent|optional },
892     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
893     { 0 }
894 };
895 /* CreateWindow (for child window, not initially visible) */
896 static const struct message WmCreateChildSeq[] = {
897     { HCBT_CREATEWND, hook },
898     { WM_NCCREATE, sent }, 
899     /* child is inserted into parent's child list after WM_NCCREATE returns */
900     { WM_NCCALCSIZE, sent|wparam, 0 },
901     { WM_CREATE, sent },
902     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
903     { WM_SIZE, sent|wparam, SIZE_RESTORED },
904     { WM_MOVE, sent },
905     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
906     { 0 }
907 };
908 /* CreateWindow (for maximized child window, not initially visible) */
909 static const struct message WmCreateMaximizedChildSeq[] = {
910     { HCBT_CREATEWND, hook },
911     { WM_NCCREATE, sent }, 
912     { WM_NCCALCSIZE, sent|wparam, 0 },
913     { WM_CREATE, sent },
914     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
915     { WM_SIZE, sent|wparam, SIZE_RESTORED },
916     { WM_MOVE, sent },
917     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
918     { WM_GETMINMAXINFO, sent },
919     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
920     { WM_NCCALCSIZE, sent|wparam, 1 },
921     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
922     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
923     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
924     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
925     { 0 }
926 };
927 /* CreateWindow (for a child window, initially visible) */
928 static const struct message WmCreateVisibleChildSeq[] = {
929     { HCBT_CREATEWND, hook },
930     { WM_NCCREATE, sent }, 
931     /* child is inserted into parent's child list after WM_NCCREATE returns */
932     { WM_NCCALCSIZE, sent|wparam, 0 },
933     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
934     { WM_CREATE, sent },
935     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
936     { WM_SIZE, sent|wparam, SIZE_RESTORED },
937     { WM_MOVE, sent },
938     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
939     { WM_SHOWWINDOW, sent|wparam, 1 },
940     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
941     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
942     { WM_ERASEBKGND, sent|parent|optional },
943     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
944     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
945     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
946     { 0 }
947 };
948 /* ShowWindow(SW_SHOW) for a not visible child window */
949 static const struct message WmShowChildSeq[] = {
950     { WM_SHOWWINDOW, sent|wparam, 1 },
951     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
952     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
953     { WM_ERASEBKGND, sent|parent|optional },
954     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
955     { 0 }
956 };
957 /* ShowWindow(SW_HIDE) for a visible child window */
958 static const struct message WmHideChildSeq[] = {
959     { WM_SHOWWINDOW, sent|wparam, 0 },
960     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
961     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
962     { WM_ERASEBKGND, sent|parent|optional },
963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
964     { 0 }
965 };
966 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
967 static const struct message WmHideChildSeq2[] = {
968     { WM_SHOWWINDOW, sent|wparam, 0 },
969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
970     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
971     { WM_ERASEBKGND, sent|parent|optional },
972     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
973     { 0 }
974 };
975 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
976  * for a not visible child window
977  */
978 static const struct message WmShowChildSeq_2[] = {
979     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
980     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
981     { WM_CHILDACTIVATE, sent },
982     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
983     { 0 }
984 };
985 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
986  * for a not visible child window
987  */
988 static const struct message WmShowChildSeq_3[] = {
989     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
990     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
991     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
992     { 0 }
993 };
994 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
995  * for a visible child window with a caption
996  */
997 static const struct message WmShowChildSeq_4[] = {
998     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
999     { WM_CHILDACTIVATE, sent },
1000     { 0 }
1001 };
1002 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1003 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1004     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1005     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1006     { WM_NCCALCSIZE, sent|wparam, 1 },
1007     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1008     { WM_CHILDACTIVATE, sent|optional },
1009     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1010     { WM_MOVE, sent|defwinproc },
1011     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1012     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1013     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1014     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1015     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1016     { WM_GETTEXT, sent|optional },
1017     { 0 }
1018 };
1019 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1020 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1021     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1022     { 0 }
1023 };
1024 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1025 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1026     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1027     { WM_GETMINMAXINFO, sent },
1028     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1029     { WM_NCCALCSIZE, sent|wparam, 1 },
1030     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1031     { WM_CHILDACTIVATE, sent },
1032     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1033     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1034     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1035     { 0 }
1036 };
1037 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1038 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1039     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1040     { 0 }
1041 };
1042 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1043 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1044     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1045     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1046     { WM_NCCALCSIZE, sent|wparam, 1 },
1047     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1048     { WM_CHILDACTIVATE, sent },
1049     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1050     { WM_MOVE, sent|defwinproc },
1051     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1052     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1053     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1054     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1055     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1056     { WM_GETTEXT, sent|optional },
1057     { 0 }
1058 };
1059 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1060 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1061     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1062     { 0 }
1063 };
1064 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1065 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1066     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1067     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1068     { WM_NCCALCSIZE, sent|wparam, 1 },
1069     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1070     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1071     { WM_MOVE, sent|defwinproc },
1072     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1073     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1074     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1075     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1076     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1077     { WM_GETTEXT, sent|optional },
1078     { 0 }
1079 };
1080 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1081 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1082     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1083     { 0 }
1084 };
1085 /* ShowWindow(SW_SHOW) for child with invisible parent */
1086 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1087     { WM_SHOWWINDOW, sent|wparam, 1 },
1088     { 0 }
1089 };
1090 /* ShowWindow(SW_HIDE) for child with invisible parent */
1091 static const struct message WmHideChildInvisibleParentSeq[] = {
1092     { WM_SHOWWINDOW, sent|wparam, 0 },
1093     { 0 }
1094 };
1095 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1096 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1097     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1098     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1099     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1100     { 0 }
1101 };
1102 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1103 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1104     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1105     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1106     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1107     { 0 }
1108 };
1109 /* DestroyWindow for a visible child window */
1110 static const struct message WmDestroyChildSeq[] = {
1111     { HCBT_DESTROYWND, hook },
1112     { 0x0090, sent|optional },
1113     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1114     { WM_SHOWWINDOW, sent|wparam, 0 },
1115     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1116     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1117     { WM_ERASEBKGND, sent|parent|optional },
1118     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1119     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1120     { WM_KILLFOCUS, sent },
1121     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1122     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1123     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1124     { WM_SETFOCUS, sent|parent },
1125     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1126     { WM_DESTROY, sent },
1127     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1128     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1129     { WM_NCDESTROY, sent },
1130     { 0 }
1131 };
1132 /* visible child window destroyed by thread exit */
1133 static const struct message WmExitThreadSeq[] = {
1134     { WM_NCDESTROY, sent },  /* actually in grandchild */
1135     { WM_PAINT, sent|parent },
1136     { WM_ERASEBKGND, sent|parent|beginpaint },
1137     { 0 }
1138 };
1139 /* DestroyWindow for a visible child window with invisible parent */
1140 static const struct message WmDestroyInvisibleChildSeq[] = {
1141     { HCBT_DESTROYWND, hook },
1142     { 0x0090, sent|optional },
1143     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1144     { WM_SHOWWINDOW, sent|wparam, 0 },
1145     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1146     { WM_DESTROY, sent },
1147     { WM_NCDESTROY, sent },
1148     { 0 }
1149 };
1150 /* Moving the mouse in nonclient area */
1151 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1152     { WM_NCHITTEST, sent },
1153     { WM_SETCURSOR, sent },
1154     { WM_NCMOUSEMOVE, posted },
1155     { 0 }
1156 };
1157 /* Moving the mouse in client area */
1158 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1159     { WM_NCHITTEST, sent },
1160     { WM_SETCURSOR, sent },
1161     { WM_MOUSEMOVE, posted },
1162     { 0 }
1163 };
1164 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1165 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1166     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1167     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1168     { WM_GETMINMAXINFO, sent|defwinproc },
1169     { WM_ENTERSIZEMOVE, sent|defwinproc },
1170     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1171     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1172     { WM_MOVE, sent|defwinproc },
1173     { WM_EXITSIZEMOVE, sent|defwinproc },
1174     { 0 }
1175 };
1176 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1177 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1178     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1179     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1180     { WM_GETMINMAXINFO, sent|defwinproc },
1181     { WM_ENTERSIZEMOVE, sent|defwinproc },
1182     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1183     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1184     { WM_GETMINMAXINFO, sent|defwinproc },
1185     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1186     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1187     { WM_GETTEXT, sent|defwinproc },
1188     { WM_ERASEBKGND, sent|defwinproc },
1189     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1190     { WM_MOVE, sent|defwinproc },
1191     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1192     { WM_EXITSIZEMOVE, sent|defwinproc },
1193     { 0 }
1194 };
1195 /* Resizing child window with MoveWindow (32) */
1196 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1197     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1198     { WM_NCCALCSIZE, sent|wparam, 1 },
1199     { WM_ERASEBKGND, sent|parent|optional },
1200     { WM_ERASEBKGND, sent|optional },
1201     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1202     { WM_MOVE, sent|defwinproc },
1203     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1204     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1205     { 0 }
1206 };
1207 /* Clicking on inactive button */
1208 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1209     { WM_NCHITTEST, sent },
1210     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1211     { WM_MOUSEACTIVATE, sent },
1212     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1213     { WM_SETCURSOR, sent },
1214     { WM_SETCURSOR, sent|parent|defwinproc },
1215     { WM_LBUTTONDOWN, posted },
1216     { WM_KILLFOCUS, posted|parent },
1217     { WM_SETFOCUS, posted },
1218     { WM_CTLCOLORBTN, posted|parent },
1219     { BM_SETSTATE, posted },
1220     { WM_CTLCOLORBTN, posted|parent },
1221     { WM_LBUTTONUP, posted },
1222     { BM_SETSTATE, posted },
1223     { WM_CTLCOLORBTN, posted|parent },
1224     { WM_COMMAND, posted|parent },
1225     { 0 }
1226 };
1227 /* Reparenting a button (16/32) */
1228 /* The last child (button) reparented gets topmost for its new parent. */
1229 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1230     { WM_SHOWWINDOW, sent|wparam, 0 },
1231     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1232     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1233     { WM_ERASEBKGND, sent|parent },
1234     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1235     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1236     { WM_CHILDACTIVATE, sent },
1237     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1238     { WM_MOVE, sent|defwinproc },
1239     { WM_SHOWWINDOW, sent|wparam, 1 },
1240     { 0 }
1241 };
1242 /* Creation of a custom dialog (32) */
1243 static const struct message WmCreateCustomDialogSeq[] = {
1244     { HCBT_CREATEWND, hook },
1245     { WM_GETMINMAXINFO, sent },
1246     { WM_NCCREATE, sent },
1247     { WM_NCCALCSIZE, sent|wparam, 0 },
1248     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1249     { WM_CREATE, sent },
1250     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1251     { WM_NOTIFYFORMAT, sent|optional },
1252     { WM_QUERYUISTATE, sent|optional },
1253     { WM_WINDOWPOSCHANGING, sent|optional },
1254     { WM_GETMINMAXINFO, sent|optional },
1255     { WM_NCCALCSIZE, sent|optional },
1256     { WM_WINDOWPOSCHANGED, sent|optional },
1257     { WM_SHOWWINDOW, sent|wparam, 1 },
1258     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1259     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1260     { HCBT_ACTIVATE, hook },
1261     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1262
1263
1264     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1265
1266     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1267
1268     { WM_NCACTIVATE, sent },
1269     { WM_GETTEXT, sent|optional|defwinproc },
1270     { WM_GETTEXT, sent|optional|defwinproc },
1271     { WM_GETTEXT, sent|optional|defwinproc },
1272     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1273     { WM_ACTIVATE, sent|wparam, 1 },
1274     { WM_GETTEXT, sent|optional },
1275     { WM_KILLFOCUS, sent|parent },
1276     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1277     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1278     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1279     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1280     { WM_SETFOCUS, sent },
1281     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1282     { WM_NCPAINT, sent|wparam, 1 },
1283     { WM_GETTEXT, sent|optional|defwinproc },
1284     { WM_GETTEXT, sent|optional|defwinproc },
1285     { WM_ERASEBKGND, sent },
1286     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1287     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1288     { WM_GETTEXT, sent|optional },
1289     { WM_GETTEXT, sent|optional },
1290     { WM_NCCALCSIZE, sent|optional },
1291     { WM_NCPAINT, sent|optional },
1292     { WM_GETTEXT, sent|optional|defwinproc },
1293     { WM_GETTEXT, sent|optional|defwinproc },
1294     { WM_ERASEBKGND, sent|optional },
1295     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1296     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1297     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1298     { WM_MOVE, sent },
1299     { 0 }
1300 };
1301 /* Calling EndDialog for a custom dialog (32) */
1302 static const struct message WmEndCustomDialogSeq[] = {
1303     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1304     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1305     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1306     { WM_GETTEXT, sent|optional },
1307     { HCBT_ACTIVATE, hook },
1308     { WM_NCACTIVATE, sent|wparam, 0 },
1309     { WM_GETTEXT, sent|optional|defwinproc },
1310     { WM_GETTEXT, sent|optional|defwinproc },
1311     { WM_ACTIVATE, sent|wparam, 0 },
1312     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1313     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1314     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1315     { WM_GETTEXT, sent|optional|defwinproc },
1316     { WM_GETTEXT, sent|optional|defwinproc },
1317     { HCBT_SETFOCUS, hook },
1318     { WM_KILLFOCUS, sent },
1319     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1320     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1321     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1322     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1323     { WM_SETFOCUS, sent|parent|defwinproc },
1324     { 0 }
1325 };
1326 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1327 static const struct message WmShowCustomDialogSeq[] = {
1328     { WM_SHOWWINDOW, sent|wparam, 1 },
1329     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1330     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1331     { HCBT_ACTIVATE, hook },
1332     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1333
1334     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1335
1336     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1337     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1338     { WM_NCACTIVATE, sent },
1339     { WM_ACTIVATE, sent|wparam, 1 },
1340     { WM_GETTEXT, sent|optional },
1341
1342     { WM_KILLFOCUS, sent|parent },
1343     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1344     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1345     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1346     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1347     { WM_SETFOCUS, sent },
1348     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1349     { WM_NCPAINT, sent|wparam, 1 },
1350     { WM_ERASEBKGND, sent },
1351     { WM_CTLCOLORDLG, sent|defwinproc },
1352     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1353     { 0 }
1354 };
1355 /* Creation and destruction of a modal dialog (32) */
1356 static const struct message WmModalDialogSeq[] = {
1357     { WM_CANCELMODE, sent|parent },
1358     { HCBT_SETFOCUS, hook },
1359     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1360     { WM_KILLFOCUS, sent|parent },
1361     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1362     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1363     { WM_ENABLE, sent|parent|wparam, 0 },
1364     { HCBT_CREATEWND, hook },
1365     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1366     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1367     { WM_SETFONT, sent },
1368     { WM_INITDIALOG, sent },
1369     { WM_CHANGEUISTATE, sent|optional },
1370     { WM_UPDATEUISTATE, sent|optional },
1371     { WM_SHOWWINDOW, sent },
1372     { HCBT_ACTIVATE, hook },
1373     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1374     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1375     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1376     { WM_NCACTIVATE, sent },
1377     { WM_GETTEXT, sent|optional },
1378     { WM_ACTIVATE, sent|wparam, 1 },
1379     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1380     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1381     { WM_NCPAINT, sent|optional },
1382     { WM_GETTEXT, sent|optional },
1383     { WM_ERASEBKGND, sent|optional },
1384     { WM_CTLCOLORDLG, sent|optional },
1385     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1386     { WM_GETTEXT, sent|optional },
1387     { WM_NCCALCSIZE, sent|optional },
1388     { WM_NCPAINT, sent|optional },
1389     { WM_GETTEXT, sent|optional },
1390     { WM_ERASEBKGND, sent|optional },
1391     { WM_CTLCOLORDLG, sent|optional },
1392     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1393     { WM_PAINT, sent|optional },
1394     { WM_CTLCOLORBTN, sent|optional },
1395     { WM_GETTITLEBARINFOEX, sent|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_ENTERIDLE, sent|parent|optional },
1415     { WM_ENTERIDLE, sent|parent|optional },
1416     { WM_TIMER, sent },
1417     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1418     { WM_ENABLE, sent|parent|wparam, 1 },
1419     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1420     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1421     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1422     { WM_GETTEXT, sent|optional },
1423     { HCBT_ACTIVATE, hook },
1424     { WM_NCACTIVATE, sent|wparam, 0 },
1425     { WM_GETTEXT, sent|optional },
1426     { WM_ACTIVATE, sent|wparam, 0 },
1427     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1428     { WM_WINDOWPOSCHANGING, sent|optional },
1429     { WM_WINDOWPOSCHANGED, sent|optional },
1430     { HCBT_SETFOCUS, hook },
1431     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1432     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1433     { WM_SETFOCUS, sent|parent|defwinproc },
1434     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1435     { HCBT_DESTROYWND, hook },
1436     { 0x0090, sent|optional },
1437     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1438     { WM_DESTROY, sent },
1439     { WM_NCDESTROY, sent },
1440     { 0 }
1441 };
1442 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1443 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1444     /* (inside dialog proc, handling WM_INITDIALOG) */
1445     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1446     { WM_NCCALCSIZE, sent },
1447     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1448     { WM_GETTEXT, sent|defwinproc },
1449     { WM_ACTIVATE, sent|parent|wparam, 0 },
1450     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1451     { WM_WINDOWPOSCHANGING, sent|parent },
1452     { WM_NCACTIVATE, sent|wparam, 1 },
1453     { WM_ACTIVATE, sent|wparam, 1 },
1454     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1455     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1456     /* (setting focus) */
1457     { WM_SHOWWINDOW, sent|wparam, 1 },
1458     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1459     { WM_NCPAINT, sent },
1460     { WM_GETTEXT, sent|defwinproc },
1461     { WM_ERASEBKGND, sent },
1462     { WM_CTLCOLORDLG, sent|defwinproc },
1463     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1464     { WM_PAINT, sent },
1465     /* (bunch of WM_CTLCOLOR* for each control) */
1466     { WM_PAINT, sent|parent },
1467     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1468     { WM_SETCURSOR, sent|parent },
1469     { 0 }
1470 };
1471 /* SetMenu for NonVisible windows with size change*/
1472 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1473     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1474     { WM_NCCALCSIZE, sent|wparam, 1 },
1475     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1476     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1477     { WM_MOVE, sent|defwinproc },
1478     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1479     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1480     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1481     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1482     { WM_GETTEXT, sent|optional },
1483     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1484     { 0 }
1485 };
1486 /* SetMenu for NonVisible windows with no size change */
1487 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1488     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1489     { WM_NCCALCSIZE, sent|wparam, 1 },
1490     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1491     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1492     { 0 }
1493 };
1494 /* SetMenu for Visible windows with size change */
1495 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1496     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1497     { WM_NCCALCSIZE, sent|wparam, 1 },
1498     { 0x0093, sent|defwinproc|optional },
1499     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1500     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1501     { 0x0093, sent|defwinproc|optional },
1502     { 0x0093, sent|defwinproc|optional },
1503     { 0x0091, sent|defwinproc|optional },
1504     { 0x0092, sent|defwinproc|optional },
1505     { WM_GETTEXT, sent|defwinproc|optional },
1506     { WM_ERASEBKGND, sent|optional },
1507     { WM_ACTIVATE, sent|optional },
1508     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1509     { WM_MOVE, sent|defwinproc },
1510     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1511     { 0x0093, sent|optional },
1512     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1513     { 0x0093, sent|defwinproc|optional },
1514     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1515     { 0x0093, sent|defwinproc|optional },
1516     { 0x0093, sent|defwinproc|optional },
1517     { 0x0091, sent|defwinproc|optional },
1518     { 0x0092, sent|defwinproc|optional },
1519     { WM_ERASEBKGND, sent|optional },
1520     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1521     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1522     { 0 }
1523 };
1524 /* SetMenu for Visible windows with no size change */
1525 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1526     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1527     { WM_NCCALCSIZE, sent|wparam, 1 },
1528     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1529     { WM_GETTEXT, sent|defwinproc|optional },
1530     { WM_ERASEBKGND, sent|optional },
1531     { WM_ACTIVATE, sent|optional },
1532     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1533     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1534     { 0 }
1535 };
1536 /* DrawMenuBar for a visible window */
1537 static const struct message WmDrawMenuBarSeq[] =
1538 {
1539     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1540     { WM_NCCALCSIZE, sent|wparam, 1 },
1541     { 0x0093, sent|defwinproc|optional },
1542     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1543     { 0x0093, sent|defwinproc|optional },
1544     { 0x0093, sent|defwinproc|optional },
1545     { 0x0091, sent|defwinproc|optional },
1546     { 0x0092, sent|defwinproc|optional },
1547     { WM_GETTEXT, sent|defwinproc|optional },
1548     { WM_ERASEBKGND, sent|optional },
1549     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1550     { 0x0093, sent|optional },
1551     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1552     { 0 }
1553 };
1554
1555 static const struct message WmSetRedrawFalseSeq[] =
1556 {
1557     { WM_SETREDRAW, sent|wparam, 0 },
1558     { 0 }
1559 };
1560
1561 static const struct message WmSetRedrawTrueSeq[] =
1562 {
1563     { WM_SETREDRAW, sent|wparam, 1 },
1564     { 0 }
1565 };
1566
1567 static const struct message WmEnableWindowSeq_1[] =
1568 {
1569     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1570     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1571     { HCBT_SETFOCUS, hook|optional },
1572     { WM_KILLFOCUS, sent|optional },
1573     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1574     { 0 }
1575 };
1576
1577 static const struct message WmEnableWindowSeq_2[] =
1578 {
1579     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1580     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1581     { 0 }
1582 };
1583
1584 static const struct message WmGetScrollRangeSeq[] =
1585 {
1586     { SBM_GETRANGE, sent },
1587     { 0 }
1588 };
1589 static const struct message WmGetScrollInfoSeq[] =
1590 {
1591     { SBM_GETSCROLLINFO, sent },
1592     { 0 }
1593 };
1594 static const struct message WmSetScrollRangeSeq[] =
1595 {
1596     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1597        sends SBM_SETSCROLLINFO.
1598      */
1599     { SBM_SETSCROLLINFO, sent },
1600     { 0 }
1601 };
1602 /* SetScrollRange for a window without a non-client area */
1603 static const struct message WmSetScrollRangeHSeq_empty[] =
1604 {
1605     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1606     { 0 }
1607 };
1608 static const struct message WmSetScrollRangeVSeq_empty[] =
1609 {
1610     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1611     { 0 }
1612 };
1613 static const struct message WmSetScrollRangeHVSeq[] =
1614 {
1615     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1616     { WM_NCCALCSIZE, sent|wparam, 1 },
1617     { WM_GETTEXT, sent|defwinproc|optional },
1618     { WM_ERASEBKGND, sent|optional },
1619     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1620     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1621     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1622     { 0 }
1623 };
1624 /* SetScrollRange for a window with a non-client area */
1625 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1626 {
1627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1628     { WM_NCCALCSIZE, sent|wparam, 1 },
1629     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1630     { WM_NCPAINT, sent|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_STYLECHANGING, sent|defwinproc|optional },
1638     { WM_STYLECHANGED, sent|defwinproc|optional },
1639     { WM_GETTEXT, sent|defwinproc|optional },
1640     { WM_GETTEXT, sent|defwinproc|optional },
1641     { WM_ERASEBKGND, sent|optional },
1642     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1643     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1644     { WM_SIZE, sent|defwinproc|optional },
1645     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1646     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1647     { WM_GETTEXT, sent|optional },
1648     { WM_GETTEXT, sent|optional },
1649     { WM_GETTEXT, sent|optional },
1650     { WM_GETTEXT, sent|optional },
1651     { 0 }
1652 };
1653 /* test if we receive the right sequence of messages */
1654 /* after calling ShowWindow( SW_SHOWNA) */
1655 static const struct message WmSHOWNAChildInvisParInvis[] = {
1656     { WM_SHOWWINDOW, sent|wparam, 1 },
1657     { 0 }
1658 };
1659 static const struct message WmSHOWNAChildVisParInvis[] = {
1660     { WM_SHOWWINDOW, sent|wparam, 1 },
1661     { 0 }
1662 };
1663 static const struct message WmSHOWNAChildVisParVis[] = {
1664     { WM_SHOWWINDOW, sent|wparam, 1 },
1665     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1666     { 0 }
1667 };
1668 static const struct message WmSHOWNAChildInvisParVis[] = {
1669     { WM_SHOWWINDOW, sent|wparam, 1 },
1670     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1671     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1672     { WM_ERASEBKGND, sent|optional },
1673     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1674     { 0 }
1675 };
1676 static const struct message WmSHOWNATopVisible[] = {
1677     { WM_SHOWWINDOW, sent|wparam, 1 },
1678     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1679     { WM_NCPAINT, sent|wparam|optional, 1 },
1680     { WM_GETTEXT, sent|defwinproc|optional },
1681     { WM_ERASEBKGND, sent|optional },
1682     { WM_WINDOWPOSCHANGED, sent|optional },
1683     { 0 }
1684 };
1685 static const struct message WmSHOWNATopInvisible[] = {
1686     { WM_NOTIFYFORMAT, sent|optional },
1687     { WM_QUERYUISTATE, sent|optional },
1688     { WM_WINDOWPOSCHANGING, sent|optional },
1689     { WM_GETMINMAXINFO, sent|optional },
1690     { WM_NCCALCSIZE, sent|optional },
1691     { WM_WINDOWPOSCHANGED, sent|optional },
1692     { WM_SHOWWINDOW, sent|wparam, 1 },
1693     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1694     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1695     { WM_NCPAINT, sent|wparam|optional, 1 },
1696     { WM_GETTEXT, sent|defwinproc|optional },
1697     { WM_ERASEBKGND, sent|optional },
1698     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1699     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1700     { WM_NCPAINT, sent|wparam|optional, 1 },
1701     { WM_ERASEBKGND, sent|optional },
1702     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1703     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1704     { WM_MOVE, sent },
1705     { 0 }
1706 };
1707
1708 static int after_end_dialog, test_def_id;
1709 static int sequence_cnt, sequence_size;
1710 static struct recvd_message* sequence;
1711 static int log_all_parent_messages;
1712 static int paint_loop_done;
1713
1714 /* user32 functions */
1715 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1716 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1717 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1718 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1719 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1720 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1721 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1722 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
1723 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
1724 /* kernel32 functions */
1725 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1726
1727 static void init_procs(void)
1728 {
1729     HMODULE user32 = GetModuleHandleA("user32.dll");
1730     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1731
1732 #define GET_PROC(dll, func) \
1733     p ## func = (void*)GetProcAddress(dll, #func); \
1734     if(!p ## func) { \
1735       trace("GetProcAddress(%s) failed\n", #func); \
1736     }
1737
1738     GET_PROC(user32, GetAncestor)
1739     GET_PROC(user32, GetMenuInfo)
1740     GET_PROC(user32, NotifyWinEvent)
1741     GET_PROC(user32, SetMenuInfo)
1742     GET_PROC(user32, SetWinEventHook)
1743     GET_PROC(user32, TrackMouseEvent)
1744     GET_PROC(user32, UnhookWinEvent)
1745     GET_PROC(user32, GetMonitorInfoA)
1746     GET_PROC(user32, MonitorFromPoint)
1747
1748     GET_PROC(kernel32, GetCPInfoExA)
1749
1750 #undef GET_PROC
1751 }
1752
1753 static const char *get_winpos_flags(UINT flags)
1754 {
1755     static char buffer[300];
1756
1757     buffer[0] = 0;
1758 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
1759     DUMP( SWP_SHOWWINDOW );
1760     DUMP( SWP_HIDEWINDOW );
1761     DUMP( SWP_NOACTIVATE );
1762     DUMP( SWP_FRAMECHANGED );
1763     DUMP( SWP_NOCOPYBITS );
1764     DUMP( SWP_NOOWNERZORDER );
1765     DUMP( SWP_NOSENDCHANGING );
1766     DUMP( SWP_DEFERERASE );
1767     DUMP( SWP_ASYNCWINDOWPOS );
1768     DUMP( SWP_NOZORDER );
1769     DUMP( SWP_NOREDRAW );
1770     DUMP( SWP_NOSIZE );
1771     DUMP( SWP_NOMOVE );
1772     DUMP( SWP_NOCLIENTSIZE );
1773     DUMP( SWP_NOCLIENTMOVE );
1774     if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
1775     return buffer + 1;
1776 #undef DUMP
1777 }
1778
1779 static BOOL ignore_message( UINT message )
1780 {
1781     /* these are always ignored */
1782     return (message >= 0xc000 ||
1783             message == WM_GETICON ||
1784             message == WM_GETOBJECT ||
1785             message == WM_TIMECHANGE ||
1786             message == WM_DISPLAYCHANGE ||
1787             message == WM_DEVICECHANGE ||
1788             message == WM_DWMNCRENDERINGCHANGED);
1789 }
1790
1791
1792 #define add_message(msg) add_message_(__LINE__,msg);
1793 static void add_message_(int line, const struct recvd_message *msg)
1794 {
1795     struct recvd_message *seq;
1796
1797     if (!sequence) 
1798     {
1799         sequence_size = 10;
1800         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
1801     }
1802     if (sequence_cnt == sequence_size) 
1803     {
1804         sequence_size *= 2;
1805         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
1806     }
1807     assert(sequence);
1808
1809     seq = &sequence[sequence_cnt];
1810     seq->hwnd = msg->hwnd;
1811     seq->message = msg->message;
1812     seq->flags = msg->flags;
1813     seq->wParam = msg->wParam;
1814     seq->lParam = msg->lParam;
1815     seq->line   = line;
1816     seq->descr  = msg->descr;
1817     seq->output[0] = 0;
1818
1819     if (msg->descr)
1820     {
1821         if (msg->flags & hook)
1822         {
1823             static const char * const CBT_code_name[10] =
1824             {
1825                 "HCBT_MOVESIZE",
1826                 "HCBT_MINMAX",
1827                 "HCBT_QS",
1828                 "HCBT_CREATEWND",
1829                 "HCBT_DESTROYWND",
1830                 "HCBT_ACTIVATE",
1831                 "HCBT_CLICKSKIPPED",
1832                 "HCBT_KEYSKIPPED",
1833                 "HCBT_SYSCOMMAND",
1834                 "HCBT_SETFOCUS"
1835             };
1836             const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
1837
1838             sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
1839                      msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
1840         }
1841         else if (msg->flags & winevent_hook)
1842         {
1843             sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
1844                      msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1845         }
1846         else
1847         {
1848             switch (msg->message)
1849             {
1850             case WM_WINDOWPOSCHANGING:
1851             case WM_WINDOWPOSCHANGED:
1852             {
1853                 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
1854
1855                 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
1856                           msg->descr, msg->hwnd,
1857                           (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
1858                           msg->wParam, msg->lParam, winpos->hwndInsertAfter,
1859                           winpos->x, winpos->y, winpos->cx, winpos->cy,
1860                           get_winpos_flags(winpos->flags) );
1861
1862                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
1863                  * in the high word for internal purposes
1864                  */
1865                 seq->wParam = winpos->flags & 0xffff;
1866                 /* We are not interested in the flags that don't match under XP and Win9x */
1867                 seq->wParam &= ~SWP_NOZORDER;
1868                 break;
1869             }
1870
1871             case WM_DRAWITEM:
1872             {
1873                 DRAW_ITEM_STRUCT di;
1874                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
1875
1876                 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
1877                          msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
1878                          dis->itemID, dis->itemAction, dis->itemState);
1879
1880                 di.u.lp = 0;
1881                 di.u.item.type = dis->CtlType;
1882                 di.u.item.ctl_id = dis->CtlID;
1883                 if (dis->CtlType == ODT_LISTBOX ||
1884                     dis->CtlType == ODT_COMBOBOX ||
1885                     dis->CtlType == ODT_MENU)
1886                     di.u.item.item_id = dis->itemID;
1887                 di.u.item.action = dis->itemAction;
1888                 di.u.item.state = dis->itemState;
1889
1890                 seq->lParam = di.u.lp;
1891                 break;
1892             }
1893             default:
1894                 if (msg->message >= 0xc000) return;  /* ignore registered messages */
1895                 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
1896                          msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
1897             }
1898             if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
1899                 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
1900         }
1901     }
1902
1903     sequence_cnt++;
1904 }
1905
1906 /* try to make sure pending X events have been processed before continuing */
1907 static void flush_events(void)
1908 {
1909     MSG msg;
1910     int diff = 200;
1911     int min_timeout = 100;
1912     DWORD time = GetTickCount() + diff;
1913
1914     while (diff > 0)
1915     {
1916         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1917         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1918         diff = time - GetTickCount();
1919     }
1920 }
1921
1922 static void flush_sequence(void)
1923 {
1924     HeapFree(GetProcessHeap(), 0, sequence);
1925     sequence = 0;
1926     sequence_cnt = sequence_size = 0;
1927 }
1928
1929 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
1930 {
1931     const struct recvd_message *actual = sequence;
1932     unsigned int count = 0;
1933
1934     trace_(file, line)("Failed sequence %s:\n", context );
1935     while (expected->message && actual->message)
1936     {
1937         if (actual->output[0])
1938         {
1939             if (expected->flags & hook)
1940             {
1941                 trace_(file, line)( "  %u: expected: hook %04x - actual: %s\n",
1942                                     count, expected->message, actual->output );
1943             }
1944             else if (expected->flags & winevent_hook)
1945             {
1946                 trace_(file, line)( "  %u: expected: winevent %04x - actual: %s\n",
1947                                     count, expected->message, actual->output );
1948             }
1949             else if (expected->flags & kbd_hook)
1950             {
1951                 trace_(file, line)( "  %u: expected: kbd %04x - actual: %s\n",
1952                                     count, expected->message, actual->output );
1953             }
1954             else
1955             {
1956                 trace_(file, line)( "  %u: expected: msg %04x - actual: %s\n",
1957                                     count, expected->message, actual->output );
1958             }
1959         }
1960
1961         if (expected->message == actual->message)
1962         {
1963             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
1964                 (expected->flags & optional))
1965             {
1966                 /* don't match messages if their defwinproc status differs */
1967                 expected++;
1968             }
1969             else
1970             {
1971                 expected++;
1972                 actual++;
1973             }
1974         }
1975         /* silently drop winevent messages if there is no support for them */
1976         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1977             expected++;
1978         else
1979         {
1980             expected++;
1981             actual++;
1982         }
1983         count++;
1984     }
1985
1986     /* optional trailing messages */
1987     while (expected->message && ((expected->flags & optional) ||
1988             ((expected->flags & winevent_hook) && !hEvent_hook)))
1989     {
1990         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1991         expected++;
1992         count++;
1993     }
1994
1995     if (expected->message)
1996     {
1997         trace_(file, line)( "  %u: expected: msg %04x - actual: nothing\n", count, expected->message );
1998         return;
1999     }
2000
2001     while (actual->message && actual->output[0])
2002     {
2003         trace_(file, line)( "  %u: expected: nothing - actual: %s\n", count, actual->output );
2004         actual++;
2005         count++;
2006     }
2007 }
2008
2009 #define ok_sequence( exp, contx, todo) \
2010         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2011
2012
2013 static void ok_sequence_(const struct message *expected_list, const char *context, int todo,
2014                          const char *file, int line)
2015 {
2016     static const struct recvd_message end_of_sequence;
2017     const struct message *expected = expected_list;
2018     const struct recvd_message *actual;
2019     int failcount = 0, dump = 0;
2020     unsigned int count = 0;
2021
2022     add_message(&end_of_sequence);
2023
2024     actual = sequence;
2025
2026     while (expected->message && actual->message)
2027     {
2028         if (expected->message == actual->message)
2029         {
2030             if (expected->flags & wparam)
2031             {
2032                 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2033                 {
2034                     todo_wine {
2035                         failcount ++;
2036                         if (strcmp(winetest_platform, "wine")) dump++;
2037                         ok_( file, line) (FALSE,
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                     }
2041                 }
2042                 else
2043                 {
2044                     ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2045                                      "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2046                                      context, count, expected->message, expected->wParam, actual->wParam);
2047                     if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2048                 }
2049
2050             }
2051             if (expected->flags & lparam)
2052             {
2053                 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2054                 {
2055                     todo_wine {
2056                         failcount ++;
2057                         if (strcmp(winetest_platform, "wine")) dump++;
2058                         ok_( file, line) (FALSE,
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                     }
2062                 }
2063                 else
2064                 {
2065                     ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2066                                      "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2067                                      context, count, expected->message, expected->lParam, actual->lParam);
2068                     if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2069                 }
2070             }
2071             if ((expected->flags & optional) &&
2072                 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2073             {
2074                 /* don't match optional messages if their defwinproc or parent status differs */
2075                 expected++;
2076                 count++;
2077                 continue;
2078             }
2079             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2080             {
2081                     todo_wine {
2082                         failcount ++;
2083                         if (strcmp(winetest_platform, "wine")) dump++;
2084                         ok_( file, line) (FALSE,
2085                             "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2086                             context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2087                     }
2088             }
2089             else
2090             {
2091                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2092                     "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2093                     context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2094                 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2095             }
2096
2097             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2098                 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2099                 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2100             if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2101
2102             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2103                 "%s: %u: the msg 0x%04x should have been %s\n",
2104                 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2105             if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2106
2107             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2108                 "%s: %u: the msg 0x%04x was expected in %s\n",
2109                 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2110             if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2111
2112             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2113                 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2114                 context, count, expected->message);
2115             if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2116
2117             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2118                 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2119                 context, count, expected->message);
2120             if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2121
2122             ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2123                 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2124                 context, count, expected->message);
2125             if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2126
2127             expected++;
2128             actual++;
2129         }
2130         /* silently drop hook messages if there is no support for them */
2131         else if ((expected->flags & optional) ||
2132                  ((expected->flags & hook) && !hCBT_hook) ||
2133                  ((expected->flags & winevent_hook) && !hEvent_hook))
2134             expected++;
2135         else if (todo)
2136         {
2137             failcount++;
2138             todo_wine {
2139                 if (strcmp(winetest_platform, "wine")) dump++;
2140                 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2141                                   context, count, expected->message, actual->message);
2142             }
2143             goto done;
2144         }
2145         else
2146         {
2147             ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2148                               context, count, expected->message, actual->message);
2149             dump++;
2150             expected++;
2151             actual++;
2152         }
2153         count++;
2154     }
2155
2156     /* skip all optional trailing messages */
2157     while (expected->message && ((expected->flags & optional) ||
2158                                  ((expected->flags & hook) && !hCBT_hook) ||
2159                                  ((expected->flags & winevent_hook) && !hEvent_hook)))
2160         expected++;
2161
2162     if (todo)
2163     {
2164         todo_wine {
2165             if (expected->message || actual->message) {
2166                 failcount++;
2167                 if (strcmp(winetest_platform, "wine")) dump++;
2168                 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2169                                   context, count, expected->message, actual->message);
2170             }
2171         }
2172     }
2173     else
2174     {
2175         if (expected->message || actual->message)
2176         {
2177             dump++;
2178             ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2179                               context, count, expected->message, actual->message);
2180         }
2181     }
2182     if( todo && !failcount) /* succeeded yet marked todo */
2183         todo_wine {
2184             if (!strcmp(winetest_platform, "wine")) dump++;
2185             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2186         }
2187
2188 done:
2189     if (dump) dump_sequence(expected_list, context, file, line);
2190     flush_sequence();
2191 }
2192
2193 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2194
2195 /******************************** MDI test **********************************/
2196
2197 /* CreateWindow for MDI frame window, initially visible */
2198 static const struct message WmCreateMDIframeSeq[] = {
2199     { HCBT_CREATEWND, hook },
2200     { WM_GETMINMAXINFO, sent },
2201     { WM_NCCREATE, sent },
2202     { WM_NCCALCSIZE, sent|wparam, 0 },
2203     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2204     { WM_CREATE, sent },
2205     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2206     { WM_NOTIFYFORMAT, sent|optional },
2207     { WM_QUERYUISTATE, sent|optional },
2208     { WM_WINDOWPOSCHANGING, sent|optional },
2209     { WM_GETMINMAXINFO, sent|optional },
2210     { WM_NCCALCSIZE, sent|optional },
2211     { WM_WINDOWPOSCHANGED, sent|optional },
2212     { WM_SHOWWINDOW, sent|wparam, 1 },
2213     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2214     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2215     { HCBT_ACTIVATE, hook },
2216     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2217     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2218     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2219     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2220     { WM_NCACTIVATE, sent },
2221     { WM_GETTEXT, sent|defwinproc|optional },
2222     { WM_ACTIVATE, sent|wparam, 1 },
2223     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2224     { HCBT_SETFOCUS, hook },
2225     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2226     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2227     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2228     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2229     /* Win9x adds SWP_NOZORDER below */
2230     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2231     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2232     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2233     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2234     { WM_MOVE, sent },
2235     { 0 }
2236 };
2237 /* DestroyWindow for MDI frame window, initially visible */
2238 static const struct message WmDestroyMDIframeSeq[] = {
2239     { HCBT_DESTROYWND, hook },
2240     { 0x0090, sent|optional },
2241     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2242     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2243     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2244     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2245     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2246     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2247     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2248     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2249     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2250     { WM_DESTROY, sent },
2251     { WM_NCDESTROY, sent },
2252     { 0 }
2253 };
2254 /* CreateWindow for MDI client window, initially visible */
2255 static const struct message WmCreateMDIclientSeq[] = {
2256     { HCBT_CREATEWND, hook },
2257     { WM_NCCREATE, sent },
2258     { WM_NCCALCSIZE, sent|wparam, 0 },
2259     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2260     { WM_CREATE, sent },
2261     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2262     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2263     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2264     { WM_MOVE, sent },
2265     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2266     { WM_SHOWWINDOW, sent|wparam, 1 },
2267     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2268     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2269     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2270     { 0 }
2271 };
2272 /* ShowWindow(SW_SHOW) for MDI client window */
2273 static const struct message WmShowMDIclientSeq[] = {
2274     { WM_SHOWWINDOW, sent|wparam, 1 },
2275     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2276     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2277     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2278     { 0 }
2279 };
2280 /* ShowWindow(SW_HIDE) for MDI client window */
2281 static const struct message WmHideMDIclientSeq[] = {
2282     { WM_SHOWWINDOW, sent|wparam, 0 },
2283     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2284     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2285     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2286     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2287     { 0 }
2288 };
2289 /* DestroyWindow for MDI client window, initially visible */
2290 static const struct message WmDestroyMDIclientSeq[] = {
2291     { HCBT_DESTROYWND, hook },
2292     { 0x0090, sent|optional },
2293     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2294     { WM_SHOWWINDOW, sent|wparam, 0 },
2295     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2296     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2297     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2298     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2299     { WM_DESTROY, sent },
2300     { WM_NCDESTROY, sent },
2301     { 0 }
2302 };
2303 /* CreateWindow for MDI child window, initially visible */
2304 static const struct message WmCreateMDIchildVisibleSeq[] = {
2305     { HCBT_CREATEWND, hook },
2306     { WM_NCCREATE, sent }, 
2307     { WM_NCCALCSIZE, sent|wparam, 0 },
2308     { WM_CREATE, sent },
2309     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2310     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2311     { WM_MOVE, sent },
2312     /* Win2k sends wparam set to
2313      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2314      * while Win9x doesn't bother to set child window id according to
2315      * CLIENTCREATESTRUCT.idFirstChild
2316      */
2317     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2318     { WM_SHOWWINDOW, sent|wparam, 1 },
2319     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2320     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2321     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2322     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2323     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2324     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2325     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2326
2327     /* Win9x: message sequence terminates here. */
2328
2329     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2330     { HCBT_SETFOCUS, hook }, /* in MDI client */
2331     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2332     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2333     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2334     { WM_SETFOCUS, sent }, /* in MDI client */
2335     { HCBT_SETFOCUS, hook },
2336     { WM_KILLFOCUS, sent }, /* in MDI client */
2337     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2338     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2339     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2340     { WM_SETFOCUS, sent|defwinproc },
2341     { WM_MDIACTIVATE, sent|defwinproc },
2342     { 0 }
2343 };
2344 /* CreateWindow for MDI child window with invisible parent */
2345 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2346     { HCBT_CREATEWND, hook },
2347     { WM_GETMINMAXINFO, sent },
2348     { WM_NCCREATE, sent }, 
2349     { WM_NCCALCSIZE, sent|wparam, 0 },
2350     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2351     { WM_CREATE, sent },
2352     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2353     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2354     { WM_MOVE, sent },
2355     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2356     { WM_SHOWWINDOW, sent|wparam, 1 },
2357     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2358     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2359     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2360     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2361
2362     /* Win9x: message sequence terminates here. */
2363
2364     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2365     { HCBT_SETFOCUS, hook }, /* in MDI client */
2366     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2367     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2368     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2369     { WM_SETFOCUS, sent }, /* in MDI client */
2370     { HCBT_SETFOCUS, hook },
2371     { WM_KILLFOCUS, sent }, /* in MDI client */
2372     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2373     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2374     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2375     { WM_SETFOCUS, sent|defwinproc },
2376     { WM_MDIACTIVATE, sent|defwinproc },
2377     { 0 }
2378 };
2379 /* DestroyWindow for MDI child window, initially visible */
2380 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2381     { HCBT_DESTROYWND, hook },
2382     /* Win2k sends wparam set to
2383      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2384      * while Win9x doesn't bother to set child window id according to
2385      * CLIENTCREATESTRUCT.idFirstChild
2386      */
2387     { 0x0090, sent|optional },
2388     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2389     { WM_SHOWWINDOW, sent|wparam, 0 },
2390     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2391     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2392     { WM_ERASEBKGND, sent|parent|optional },
2393     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2394
2395     /* { WM_DESTROY, sent }
2396      * Win9x: message sequence terminates here.
2397      */
2398
2399     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2400     { WM_KILLFOCUS, sent },
2401     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2402     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2403     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2404     { WM_SETFOCUS, sent }, /* in MDI client */
2405
2406     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2407     { WM_KILLFOCUS, sent }, /* in MDI client */
2408     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2409     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2410     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2411     { WM_SETFOCUS, sent }, /* in MDI client */
2412
2413     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2414
2415     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2416     { WM_KILLFOCUS, sent },
2417     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2418     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2419     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2420     { WM_SETFOCUS, sent }, /* in MDI client */
2421
2422     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2423     { WM_KILLFOCUS, sent }, /* in MDI client */
2424     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2425     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2426     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2427     { WM_SETFOCUS, sent }, /* in MDI client */
2428
2429     { WM_DESTROY, sent },
2430
2431     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2432     { WM_KILLFOCUS, sent },
2433     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2434     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2435     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2436     { WM_SETFOCUS, sent }, /* in MDI client */
2437
2438     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2439     { WM_KILLFOCUS, sent }, /* in MDI client */
2440     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2441     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2442     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2443     { WM_SETFOCUS, sent }, /* in MDI client */
2444
2445     { WM_NCDESTROY, sent },
2446     { 0 }
2447 };
2448 /* CreateWindow for MDI child window, initially invisible */
2449 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2450     { HCBT_CREATEWND, hook },
2451     { WM_NCCREATE, sent }, 
2452     { WM_NCCALCSIZE, sent|wparam, 0 },
2453     { WM_CREATE, sent },
2454     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2455     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2456     { WM_MOVE, sent },
2457     /* Win2k sends wparam set to
2458      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2459      * while Win9x doesn't bother to set child window id according to
2460      * CLIENTCREATESTRUCT.idFirstChild
2461      */
2462     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2463     { 0 }
2464 };
2465 /* DestroyWindow for MDI child window, initially invisible */
2466 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2467     { HCBT_DESTROYWND, hook },
2468     /* Win2k sends wparam set to
2469      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2470      * while Win9x doesn't bother to set child window id according to
2471      * CLIENTCREATESTRUCT.idFirstChild
2472      */
2473     { 0x0090, sent|optional },
2474     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2475     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2476     { WM_DESTROY, sent },
2477     { WM_NCDESTROY, sent },
2478     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2479     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2480     { 0 }
2481 };
2482 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2483 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2484     { HCBT_CREATEWND, hook },
2485     { WM_NCCREATE, sent }, 
2486     { WM_NCCALCSIZE, sent|wparam, 0 },
2487     { WM_CREATE, sent },
2488     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2489     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2490     { WM_MOVE, sent },
2491     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2492     { WM_GETMINMAXINFO, sent },
2493     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2494     { WM_NCCALCSIZE, sent|wparam, 1 },
2495     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2496     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2497      /* in MDI frame */
2498     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2499     { WM_NCCALCSIZE, sent|wparam, 1 },
2500     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2501     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2502     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2503     /* Win2k sends wparam set to
2504      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2505      * while Win9x doesn't bother to set child window id according to
2506      * CLIENTCREATESTRUCT.idFirstChild
2507      */
2508     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2509     { WM_SHOWWINDOW, sent|wparam, 1 },
2510     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2511     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2512     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2513     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2514     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2515     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2516     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2517
2518     /* Win9x: message sequence terminates here. */
2519
2520     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2521     { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2522     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2523     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2524     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2525     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2526     { HCBT_SETFOCUS, hook|optional },
2527     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2528     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2529     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2530     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2531     { WM_SETFOCUS, sent|defwinproc|optional },
2532     { WM_MDIACTIVATE, sent|defwinproc|optional },
2533      /* in MDI frame */
2534     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2535     { WM_NCCALCSIZE, sent|wparam, 1 },
2536     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2537     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2538     { 0 }
2539 };
2540 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2541 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2542     /* restore the 1st MDI child */
2543     { WM_SETREDRAW, sent|wparam, 0 },
2544     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2545     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2546     { WM_NCCALCSIZE, sent|wparam, 1 },
2547     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2548     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2549     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2550      /* in MDI frame */
2551     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2552     { WM_NCCALCSIZE, sent|wparam, 1 },
2553     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2554     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2555     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2556     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2557     /* create the 2nd MDI child */
2558     { HCBT_CREATEWND, hook },
2559     { WM_NCCREATE, sent }, 
2560     { WM_NCCALCSIZE, sent|wparam, 0 },
2561     { WM_CREATE, sent },
2562     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2563     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2564     { WM_MOVE, sent },
2565     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2566     { WM_GETMINMAXINFO, sent },
2567     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2568     { WM_NCCALCSIZE, sent|wparam, 1 },
2569     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2570     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2571     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2572      /* in MDI frame */
2573     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2574     { WM_NCCALCSIZE, sent|wparam, 1 },
2575     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2576     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2577     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2578     /* Win2k sends wparam set to
2579      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2580      * while Win9x doesn't bother to set child window id according to
2581      * CLIENTCREATESTRUCT.idFirstChild
2582      */
2583     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2584     { WM_SHOWWINDOW, sent|wparam, 1 },
2585     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2586     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2587     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2588     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2589     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2590     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2591
2592     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2593     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2594
2595     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2596
2597     /* Win9x: message sequence terminates here. */
2598
2599     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2600     { HCBT_SETFOCUS, hook },
2601     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2602     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2603     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2604     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2605     { WM_SETFOCUS, sent }, /* in MDI client */
2606     { HCBT_SETFOCUS, hook },
2607     { WM_KILLFOCUS, sent }, /* in MDI client */
2608     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2609     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2610     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2611     { WM_SETFOCUS, sent|defwinproc },
2612
2613     { WM_MDIACTIVATE, sent|defwinproc },
2614      /* in MDI frame */
2615     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2616     { WM_NCCALCSIZE, sent|wparam, 1 },
2617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2618     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2619     { 0 }
2620 };
2621 /* WM_MDICREATE MDI child window, initially visible and maximized */
2622 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2623     { WM_MDICREATE, sent },
2624     { HCBT_CREATEWND, hook },
2625     { WM_NCCREATE, sent }, 
2626     { WM_NCCALCSIZE, sent|wparam, 0 },
2627     { WM_CREATE, sent },
2628     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2629     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2630     { WM_MOVE, sent },
2631     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2632     { WM_GETMINMAXINFO, sent },
2633     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2634     { WM_NCCALCSIZE, sent|wparam, 1 },
2635     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2636     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2637
2638      /* in MDI frame */
2639     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2640     { WM_NCCALCSIZE, sent|wparam, 1 },
2641     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2642     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2643     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2644
2645     /* Win2k sends wparam set to
2646      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2647      * while Win9x doesn't bother to set child window id according to
2648      * CLIENTCREATESTRUCT.idFirstChild
2649      */
2650     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2651     { WM_SHOWWINDOW, sent|wparam, 1 },
2652     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2653
2654     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2655
2656     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2657     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2658     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2659
2660     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2661     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2662
2663     /* Win9x: message sequence terminates here. */
2664
2665     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2666     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2667     { HCBT_SETFOCUS, hook }, /* in MDI client */
2668     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2669     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2670     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2671     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2672     { HCBT_SETFOCUS, hook|optional },
2673     { WM_KILLFOCUS, sent }, /* in MDI client */
2674     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2675     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2676     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2677     { WM_SETFOCUS, sent|defwinproc },
2678
2679     { WM_MDIACTIVATE, sent|defwinproc },
2680
2681      /* in MDI child */
2682     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2683     { WM_NCCALCSIZE, sent|wparam, 1 },
2684     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2685     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2686
2687      /* in MDI frame */
2688     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2689     { WM_NCCALCSIZE, sent|wparam, 1 },
2690     { 0x0093, sent|defwinproc|optional },
2691     { 0x0093, sent|defwinproc|optional },
2692     { 0x0093, sent|defwinproc|optional },
2693     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2694     { WM_MOVE, sent|defwinproc },
2695     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2696
2697      /* in MDI client */
2698     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2699     { WM_NCCALCSIZE, sent|wparam, 1 },
2700     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2701     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2702
2703      /* in MDI child */
2704     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2705     { WM_NCCALCSIZE, sent|wparam, 1 },
2706     { 0x0093, sent|optional },
2707     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2708     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2709
2710     { 0x0093, sent|optional },
2711     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2712     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2713     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2714     { 0x0093, sent|defwinproc|optional },
2715     { 0x0093, sent|defwinproc|optional },
2716     { 0x0093, sent|defwinproc|optional },
2717     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2718     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2719
2720     { 0 }
2721 };
2722 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2723 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2724     { HCBT_CREATEWND, hook },
2725     { WM_GETMINMAXINFO, sent },
2726     { WM_NCCREATE, sent }, 
2727     { WM_NCCALCSIZE, sent|wparam, 0 },
2728     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2729     { WM_CREATE, sent },
2730     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2731     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2732     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2733     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2734     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
2735     { WM_MOVE, sent },
2736     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2737     { WM_GETMINMAXINFO, sent },
2738     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2739     { WM_GETMINMAXINFO, sent|defwinproc },
2740     { WM_NCCALCSIZE, sent|wparam, 1 },
2741     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
2742     { WM_MOVE, sent|defwinproc },
2743     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2744      /* in MDI frame */
2745     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2746     { WM_NCCALCSIZE, sent|wparam, 1 },
2747     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2748     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2749     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2750     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2751     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2752     /* Win2k sends wparam set to
2753      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2754      * while Win9x doesn't bother to set child window id according to
2755      * CLIENTCREATESTRUCT.idFirstChild
2756      */
2757     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2758     { 0 }
2759 };
2760 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2761 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2762     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2763     { HCBT_SYSCOMMAND, hook },
2764     { WM_CLOSE, sent|defwinproc },
2765     { WM_MDIDESTROY, sent }, /* in MDI client */
2766
2767     /* bring the 1st MDI child to top */
2768     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2769     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2770
2771     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2772
2773     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2774     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2775     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2776
2777     /* maximize the 1st MDI child */
2778     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2779     { WM_GETMINMAXINFO, sent|defwinproc },
2780     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2781     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2782     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2783     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2784     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2785
2786     /* restore the 2nd MDI child */
2787     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2788     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2789     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2790     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2791
2792     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2793
2794     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2795     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2796
2797     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2798
2799     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2800      /* in MDI frame */
2801     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2802     { WM_NCCALCSIZE, sent|wparam, 1 },
2803     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2804     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2805     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2806
2807     /* bring the 1st MDI child to top */
2808     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2809     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2810     { HCBT_SETFOCUS, hook },
2811     { WM_KILLFOCUS, sent|defwinproc },
2812     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2813     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2814     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2815     { WM_SETFOCUS, sent }, /* in MDI client */
2816     { HCBT_SETFOCUS, hook },
2817     { WM_KILLFOCUS, sent }, /* in MDI client */
2818     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2819     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2820     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2821     { WM_SETFOCUS, sent|defwinproc },
2822     { WM_MDIACTIVATE, sent|defwinproc },
2823     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2824
2825     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2826     { WM_SHOWWINDOW, sent|wparam, 1 },
2827     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2828     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2829     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2830     { WM_MDIREFRESHMENU, sent },
2831
2832     { HCBT_DESTROYWND, hook },
2833     /* Win2k sends wparam set to
2834      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2835      * while Win9x doesn't bother to set child window id according to
2836      * CLIENTCREATESTRUCT.idFirstChild
2837      */
2838     { 0x0090, sent|defwinproc|optional },
2839     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2840     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2841     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2842     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2843     { WM_ERASEBKGND, sent|parent|optional },
2844     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2845
2846     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2847     { WM_DESTROY, sent|defwinproc },
2848     { WM_NCDESTROY, sent|defwinproc },
2849     { 0 }
2850 };
2851 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2852 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2853     { WM_MDIDESTROY, sent }, /* in MDI client */
2854     { WM_SHOWWINDOW, sent|wparam, 0 },
2855     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2856     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2857     { WM_ERASEBKGND, sent|parent|optional },
2858     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2859
2860     { HCBT_SETFOCUS, hook },
2861     { WM_KILLFOCUS, sent },
2862     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2863     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2864     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2865     { WM_SETFOCUS, sent }, /* in MDI client */
2866     { HCBT_SETFOCUS, hook },
2867     { WM_KILLFOCUS, sent }, /* in MDI client */
2868     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2869     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2870     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2871     { WM_SETFOCUS, sent },
2872
2873      /* in MDI child */
2874     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2875     { WM_NCCALCSIZE, sent|wparam, 1 },
2876     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2877     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2878
2879      /* in MDI frame */
2880     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2881     { WM_NCCALCSIZE, sent|wparam, 1 },
2882     { 0x0093, sent|defwinproc|optional },
2883     { 0x0093, sent|defwinproc|optional },
2884     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2885     { WM_MOVE, sent|defwinproc },
2886     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2887
2888      /* in MDI client */
2889     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2890     { WM_NCCALCSIZE, sent|wparam, 1 },
2891     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2892     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2893
2894      /* in MDI child */
2895     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2896     { WM_NCCALCSIZE, sent|wparam, 1 },
2897     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2898     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2899
2900      /* in MDI child */
2901     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2902     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2903     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2904     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2905
2906      /* in MDI frame */
2907     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2908     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2909     { 0x0093, sent|defwinproc|optional },
2910     { 0x0093, sent|defwinproc|optional },
2911     { 0x0093, sent|defwinproc|optional },
2912     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2913     { WM_MOVE, sent|defwinproc },
2914     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2915
2916      /* in MDI client */
2917     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2918     { WM_NCCALCSIZE, sent|wparam, 1 },
2919     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2920     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2921
2922      /* in MDI child */
2923     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2924     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2925     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2926     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2927     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2928     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2929
2930     { 0x0093, sent|defwinproc|optional },
2931     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2932     { 0x0093, sent|defwinproc|optional },
2933     { 0x0093, sent|defwinproc|optional },
2934     { 0x0093, sent|defwinproc|optional },
2935     { 0x0093, sent|optional },
2936
2937     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2938     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2939     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2940     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2941     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2942
2943      /* in MDI frame */
2944     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2945     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2946     { 0x0093, sent|defwinproc|optional },
2947     { 0x0093, sent|defwinproc|optional },
2948     { 0x0093, sent|defwinproc|optional },
2949     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2950     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2951     { 0x0093, sent|optional },
2952
2953     { WM_NCACTIVATE, sent|wparam, 0 },
2954     { WM_MDIACTIVATE, sent },
2955
2956     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2957     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2958     { WM_NCCALCSIZE, sent|wparam, 1 },
2959
2960     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2961
2962     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2964     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2965
2966      /* in MDI child */
2967     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2968     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2969     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2970     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2971
2972      /* in MDI frame */
2973     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2974     { WM_NCCALCSIZE, sent|wparam, 1 },
2975     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2976     { WM_MOVE, sent|defwinproc },
2977     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2978
2979      /* in MDI client */
2980     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2981     { WM_NCCALCSIZE, sent|wparam, 1 },
2982     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2983     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2984     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2985     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2986     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2987     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2988     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2989
2990     { HCBT_SETFOCUS, hook },
2991     { WM_KILLFOCUS, sent },
2992     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2993     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2994     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2995     { WM_SETFOCUS, sent }, /* in MDI client */
2996
2997     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2998
2999     { HCBT_DESTROYWND, hook },
3000     /* Win2k sends wparam set to
3001      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3002      * while Win9x doesn't bother to set child window id according to
3003      * CLIENTCREATESTRUCT.idFirstChild
3004      */
3005     { 0x0090, sent|optional },
3006     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3007
3008     { WM_SHOWWINDOW, sent|wparam, 0 },
3009     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3010     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3011     { WM_ERASEBKGND, sent|parent|optional },
3012     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3013
3014     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3015     { WM_DESTROY, sent },
3016     { WM_NCDESTROY, sent },
3017     { 0 }
3018 };
3019 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3020 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3021     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3022     { WM_GETMINMAXINFO, sent },
3023     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3024     { WM_NCCALCSIZE, sent|wparam, 1 },
3025     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3026     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3027
3028     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3029     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3030     { HCBT_SETFOCUS, hook|optional },
3031     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3032     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3033     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3034     { HCBT_SETFOCUS, hook|optional },
3035     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3036     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3037     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3038     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3039     { WM_SETFOCUS, sent|optional|defwinproc },
3040     { WM_MDIACTIVATE, sent|optional|defwinproc },
3041     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3042     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3043      /* in MDI frame */
3044     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3045     { WM_NCCALCSIZE, sent|wparam, 1 },
3046     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3047     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3048     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3049     { 0 }
3050 };
3051 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3052 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3053     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3054     { WM_GETMINMAXINFO, sent },
3055     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3056     { WM_GETMINMAXINFO, sent|defwinproc },
3057     { WM_NCCALCSIZE, sent|wparam, 1 },
3058     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3059     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3060
3061     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3062     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3063     { HCBT_SETFOCUS, hook|optional },
3064     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3065     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3066     { WM_SETFOCUS, sent|optional }, /* in MDI client */
3067     { HCBT_SETFOCUS, hook|optional },
3068     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3069     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3070     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3071     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3072     { WM_SETFOCUS, sent|defwinproc|optional },
3073     { WM_MDIACTIVATE, sent|defwinproc|optional },
3074     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3075     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3076     { 0 }
3077 };
3078 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3079 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3080     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3081     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3082     { WM_GETMINMAXINFO, sent },
3083     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3084     { WM_GETMINMAXINFO, sent|defwinproc },
3085     { WM_NCCALCSIZE, sent|wparam, 1 },
3086     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3087     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3088     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3089     { WM_MOVE, sent|defwinproc },
3090     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3091
3092     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3093     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3094     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3095     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3096     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3097     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3098      /* in MDI frame */
3099     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3100     { WM_NCCALCSIZE, sent|wparam, 1 },
3101     { 0x0093, sent|defwinproc|optional },
3102     { 0x0094, sent|defwinproc|optional },
3103     { 0x0094, sent|defwinproc|optional },
3104     { 0x0094, sent|defwinproc|optional },
3105     { 0x0094, sent|defwinproc|optional },
3106     { 0x0093, sent|defwinproc|optional },
3107     { 0x0093, sent|defwinproc|optional },
3108     { 0x0091, sent|defwinproc|optional },
3109     { 0x0092, sent|defwinproc|optional },
3110     { 0x0092, sent|defwinproc|optional },
3111     { 0x0092, sent|defwinproc|optional },
3112     { 0x0092, sent|defwinproc|optional },
3113     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3114     { WM_MOVE, sent|defwinproc },
3115     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3116     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3117      /* in MDI client */
3118     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3119     { WM_NCCALCSIZE, sent|wparam, 1 },
3120     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3121     { WM_SIZE, sent|wparam, SIZE_RESTORED },
3122      /* in MDI child */
3123     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3124     { WM_GETMINMAXINFO, sent|defwinproc },
3125     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3126     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3127     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3128     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3129     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3130     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3131     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3132     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3133      /* in MDI frame */
3134     { 0x0093, sent|optional },
3135     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3136     { 0x0093, sent|defwinproc|optional },
3137     { 0x0093, sent|defwinproc|optional },
3138     { 0x0093, sent|defwinproc|optional },
3139     { 0x0091, sent|defwinproc|optional },
3140     { 0x0092, sent|defwinproc|optional },
3141     { 0x0092, sent|defwinproc|optional },
3142     { 0x0092, sent|defwinproc|optional },
3143     { 0x0092, sent|defwinproc|optional },
3144     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3145     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3146     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3147     { 0 }
3148 };
3149 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3150 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3151     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3152     { WM_GETMINMAXINFO, sent },
3153     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3154     { WM_NCCALCSIZE, sent|wparam, 1 },
3155     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3156     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3157     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3158      /* in MDI frame */
3159     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3160     { WM_NCCALCSIZE, sent|wparam, 1 },
3161     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3162     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3163     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3164     { 0 }
3165 };
3166 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3167 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3168     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3169     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3170     { WM_NCCALCSIZE, sent|wparam, 1 },
3171     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3172     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3173     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3174      /* in MDI frame */
3175     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3176     { WM_NCCALCSIZE, sent|wparam, 1 },
3177     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3178     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3179     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3180     { 0 }
3181 };
3182 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3183 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3184     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3185     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3186     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3187     { WM_NCCALCSIZE, sent|wparam, 1 },
3188     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3189     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3190     { WM_MOVE, sent|defwinproc },
3191     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3192     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3193     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3194     { HCBT_SETFOCUS, hook },
3195     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3196     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3197     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3198     { WM_SETFOCUS, sent },
3199     { 0 }
3200 };
3201 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3202 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3203     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3204     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3205     { WM_NCCALCSIZE, sent|wparam, 1 },
3206     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3207     { WM_MOVE, sent|defwinproc },
3208     { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3209     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3210     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3211     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3212     /* FIXME: Wine creates an icon/title window while Windows doesn't */
3213     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3214     { 0 }
3215 };
3216 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3217 static const struct message WmRestoreMDIchildInisibleSeq[] = {
3218     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3219     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
3220     { WM_NCCALCSIZE, sent|wparam, 1 },
3221     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3222     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3223     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3224     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3225      /* in MDI frame */
3226     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3227     { WM_NCCALCSIZE, sent|wparam, 1 },
3228     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3229     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3230     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3231     { 0 }
3232 };
3233
3234 static HWND mdi_client;
3235 static WNDPROC old_mdi_client_proc;
3236
3237 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3238 {
3239     struct recvd_message msg;
3240
3241     /* do not log painting messages */
3242     if (message != WM_PAINT &&
3243         message != WM_NCPAINT &&
3244         message != WM_SYNCPAINT &&
3245         message != WM_ERASEBKGND &&
3246         message != WM_NCHITTEST &&
3247         message != WM_GETTEXT &&
3248         message != WM_MDIGETACTIVE &&
3249         !ignore_message( message ))
3250     {
3251         msg.hwnd = hwnd;
3252         msg.message = message;
3253         msg.flags = sent|wparam|lparam;
3254         msg.wParam = wParam;
3255         msg.lParam = lParam;
3256         msg.descr = "mdi client";
3257         add_message(&msg);
3258     }
3259
3260     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3261 }
3262
3263 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3264 {
3265     static LONG defwndproc_counter = 0;
3266     LRESULT ret;
3267     struct recvd_message msg;
3268
3269     /* do not log painting messages */
3270     if (message != WM_PAINT &&
3271         message != WM_NCPAINT &&
3272         message != WM_SYNCPAINT &&
3273         message != WM_ERASEBKGND &&
3274         message != WM_NCHITTEST &&
3275         message != WM_GETTEXT &&
3276         !ignore_message( message ))
3277     {
3278         switch (message)
3279         {
3280             case WM_MDIACTIVATE:
3281             {
3282                 HWND active, client = GetParent(hwnd);
3283
3284                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3285
3286                 if (hwnd == (HWND)lParam) /* if we are being activated */
3287                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3288                 else
3289                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3290                 break;
3291             }
3292         }
3293
3294         msg.hwnd = hwnd;
3295         msg.message = message;
3296         msg.flags = sent|wparam|lparam;
3297         if (defwndproc_counter) msg.flags |= defwinproc;
3298         msg.wParam = wParam;
3299         msg.lParam = lParam;
3300         msg.descr = "mdi child";
3301         add_message(&msg);
3302     }
3303
3304     defwndproc_counter++;
3305     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3306     defwndproc_counter--;
3307
3308     return ret;
3309 }
3310
3311 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3312 {
3313     static LONG defwndproc_counter = 0;
3314     LRESULT ret;
3315     struct recvd_message msg;
3316
3317     /* do not log painting messages */
3318     if (message != WM_PAINT &&
3319         message != WM_NCPAINT &&
3320         message != WM_SYNCPAINT &&
3321         message != WM_ERASEBKGND &&
3322         message != WM_NCHITTEST &&
3323         message != WM_GETTEXT &&
3324         !ignore_message( message ))
3325     {
3326         msg.hwnd = hwnd;
3327         msg.message = message;
3328         msg.flags = sent|wparam|lparam;
3329         if (defwndproc_counter) msg.flags |= defwinproc;
3330         msg.wParam = wParam;
3331         msg.lParam = lParam;
3332         msg.descr = "mdi frame";
3333         add_message(&msg);
3334     }
3335
3336     defwndproc_counter++;
3337     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3338     defwndproc_counter--;
3339
3340     return ret;
3341 }
3342
3343 static BOOL mdi_RegisterWindowClasses(void)
3344 {
3345     WNDCLASSA cls;
3346
3347     cls.style = 0;
3348     cls.lpfnWndProc = mdi_frame_wnd_proc;
3349     cls.cbClsExtra = 0;
3350     cls.cbWndExtra = 0;
3351     cls.hInstance = GetModuleHandleA(0);
3352     cls.hIcon = 0;
3353     cls.hCursor = LoadCursorA(0, IDC_ARROW);
3354     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3355     cls.lpszMenuName = NULL;
3356     cls.lpszClassName = "MDI_frame_class";
3357     if (!RegisterClassA(&cls)) return FALSE;
3358
3359     cls.lpfnWndProc = mdi_child_wnd_proc;
3360     cls.lpszClassName = "MDI_child_class";
3361     if (!RegisterClassA(&cls)) return FALSE;
3362
3363     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3364     old_mdi_client_proc = cls.lpfnWndProc;
3365     cls.hInstance = GetModuleHandleA(0);
3366     cls.lpfnWndProc = mdi_client_hook_proc;
3367     cls.lpszClassName = "MDI_client_class";
3368     if (!RegisterClassA(&cls)) assert(0);
3369
3370     return TRUE;
3371 }
3372
3373 static void test_mdi_messages(void)
3374 {
3375     MDICREATESTRUCTA mdi_cs;
3376     CLIENTCREATESTRUCT client_cs;
3377     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3378     BOOL zoomed;
3379     RECT rc;
3380     HMENU hMenu = CreateMenu();
3381
3382     if (!mdi_RegisterWindowClasses()) assert(0);
3383
3384     flush_sequence();
3385
3386     trace("creating MDI frame window\n");
3387     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3388                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3389                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3390                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3391                                 GetDesktopWindow(), hMenu,
3392                                 GetModuleHandleA(0), NULL);
3393     assert(mdi_frame);
3394     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3395
3396     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3397     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3398
3399     trace("creating MDI client window\n");
3400     GetClientRect(mdi_frame, &rc);
3401     client_cs.hWindowMenu = 0;
3402     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3403     mdi_client = CreateWindowExA(0, "MDI_client_class",
3404                                  NULL,
3405                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3406                                  rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3407                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3408     assert(mdi_client);
3409     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3410
3411     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3412     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3413
3414     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3415     ok(!active_child, "wrong active MDI child %p\n", active_child);
3416     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3417
3418     SetFocus(0);
3419     flush_sequence();
3420
3421     trace("creating invisible MDI child window\n");
3422     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3423                                 WS_CHILD,
3424                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3425                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3426     assert(mdi_child);
3427
3428     flush_sequence();
3429     ShowWindow(mdi_child, SW_SHOWNORMAL);
3430     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3431
3432     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3433     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3434
3435     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3436     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3437
3438     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3439     ok(!active_child, "wrong active MDI child %p\n", active_child);
3440     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3441
3442     ShowWindow(mdi_child, SW_HIDE);
3443     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3444     flush_sequence();
3445
3446     ShowWindow(mdi_child, SW_SHOW);
3447     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3448
3449     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3450     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3451
3452     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3453     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3454
3455     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3456     ok(!active_child, "wrong active MDI child %p\n", active_child);
3457     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3458
3459     DestroyWindow(mdi_child);
3460     flush_sequence();
3461
3462     trace("creating visible MDI child window\n");
3463     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3464                                 WS_CHILD | WS_VISIBLE,
3465                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3466                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3467     assert(mdi_child);
3468     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3469
3470     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3471     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3472
3473     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3474     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3475
3476     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3477     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3478     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3479     flush_sequence();
3480
3481     DestroyWindow(mdi_child);
3482     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3483
3484     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3485     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3486
3487     /* Win2k: MDI client still returns a just destroyed child as active
3488      * Win9x: MDI client returns 0
3489      */
3490     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3491     ok(active_child == mdi_child || /* win2k */
3492        !active_child, /* win9x */
3493        "wrong active MDI child %p\n", active_child);
3494     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3495
3496     flush_sequence();
3497
3498     trace("creating invisible MDI child window\n");
3499     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3500                                 WS_CHILD,
3501                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3502                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3503     assert(mdi_child2);
3504     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3505
3506     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3507     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3508
3509     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3510     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3511
3512     /* Win2k: MDI client still returns a just destroyed child as active
3513      * Win9x: MDI client returns mdi_child2
3514      */
3515     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3516     ok(active_child == mdi_child || /* win2k */
3517        active_child == mdi_child2, /* win9x */
3518        "wrong active MDI child %p\n", active_child);
3519     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3520     flush_sequence();
3521
3522     ShowWindow(mdi_child2, SW_MAXIMIZE);
3523     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3524
3525     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3526     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3527
3528     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3529     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3530     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3531     flush_sequence();
3532
3533     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3534     ok(GetFocus() == mdi_child2 || /* win2k */
3535        GetFocus() == 0, /* win9x */
3536        "wrong focus window %p\n", GetFocus());
3537
3538     SetFocus(0);
3539     flush_sequence();
3540
3541     ShowWindow(mdi_child2, SW_HIDE);
3542     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3543
3544     ShowWindow(mdi_child2, SW_RESTORE);
3545     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3546     flush_sequence();
3547
3548     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3549     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3550
3551     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3552     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3553     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3554     flush_sequence();
3555
3556     SetFocus(0);
3557     flush_sequence();
3558
3559     ShowWindow(mdi_child2, SW_HIDE);
3560     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3561
3562     ShowWindow(mdi_child2, SW_SHOW);
3563     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):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_MAXIMIZE);
3569     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3570
3571     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3572     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3573
3574     ShowWindow(mdi_child2, SW_RESTORE);
3575     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3576
3577     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3578     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3579
3580     ShowWindow(mdi_child2, SW_MINIMIZE);
3581     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3582
3583     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3584     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3585
3586     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3587     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3588     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3589     flush_sequence();
3590
3591     ShowWindow(mdi_child2, SW_RESTORE);
3592     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
3593
3594     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3595     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3596
3597     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3598     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3599     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3600     flush_sequence();
3601
3602     SetFocus(0);
3603     flush_sequence();
3604
3605     ShowWindow(mdi_child2, SW_HIDE);
3606     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3607
3608     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3609     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3610
3611     DestroyWindow(mdi_child2);
3612     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3613
3614     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3615     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3616
3617     /* test for maximized MDI children */
3618     trace("creating maximized visible MDI child window 1\n");
3619     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3620                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3621                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3622                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3623     assert(mdi_child);
3624     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3625     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3626
3627     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3628     ok(GetFocus() == mdi_child || /* win2k */
3629        GetFocus() == 0, /* win9x */
3630        "wrong focus window %p\n", GetFocus());
3631
3632     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3633     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3634     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3635     flush_sequence();
3636
3637     trace("creating maximized visible MDI child window 2\n");
3638     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3639                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3640                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3641                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3642     assert(mdi_child2);
3643     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3644     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3645     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3646
3647     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3648     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3649
3650     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3651     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3652     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3653     flush_sequence();
3654
3655     trace("destroying maximized visible MDI child window 2\n");
3656     DestroyWindow(mdi_child2);
3657     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3658
3659     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3660
3661     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3662     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3663
3664     /* Win2k: MDI client still returns a just destroyed child as active
3665      * Win9x: MDI client returns 0
3666      */
3667     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3668     ok(active_child == mdi_child2 || /* win2k */
3669        !active_child, /* win9x */
3670        "wrong active MDI child %p\n", active_child);
3671     flush_sequence();
3672
3673     ShowWindow(mdi_child, SW_MAXIMIZE);
3674     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3675     flush_sequence();
3676
3677     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3678     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3679
3680     trace("re-creating maximized visible MDI child window 2\n");
3681     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3682                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3683                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3684                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3685     assert(mdi_child2);
3686     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3687     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3688     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3689
3690     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3691     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3692
3693     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3694     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3695     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3696     flush_sequence();
3697
3698     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3699     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3700     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3701
3702     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3703     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3704     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3705
3706     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3707     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3708     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3709     flush_sequence();
3710
3711     DestroyWindow(mdi_child);
3712     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3713
3714     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3715     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3716
3717     /* Win2k: MDI client still returns a just destroyed child as active
3718      * Win9x: MDI client returns 0
3719      */
3720     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3721     ok(active_child == mdi_child || /* win2k */
3722        !active_child, /* win9x */
3723        "wrong active MDI child %p\n", active_child);
3724     flush_sequence();
3725
3726     trace("creating maximized invisible MDI child window\n");
3727     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3728                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3729                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3730                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3731     assert(mdi_child2);
3732     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3733     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3734     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3735     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3736
3737     /* Win2k: MDI client still returns a just destroyed child as active
3738      * Win9x: MDI client returns 0
3739      */
3740     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3741     ok(active_child == mdi_child || /* win2k */
3742        !active_child || active_child == mdi_child2, /* win9x */
3743        "wrong active MDI child %p\n", active_child);
3744     flush_sequence();
3745
3746     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3747     ShowWindow(mdi_child2, SW_MAXIMIZE);
3748     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3749     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3750     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3751     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3752
3753     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3754     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3755     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3756     flush_sequence();
3757
3758     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3759     flush_sequence();
3760
3761     /* end of test for maximized MDI children */
3762     SetFocus(0);
3763     flush_sequence();
3764     trace("creating maximized visible MDI child window 1(Switch test)\n");
3765     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3766                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3767                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3768                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3769     assert(mdi_child);
3770     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3771     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3772
3773     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3774     ok(GetFocus() == mdi_child || /* win2k */
3775        GetFocus() == 0, /* win9x */
3776        "wrong focus window %p(Switch test)\n", GetFocus());
3777
3778     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3779     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3780     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3781     flush_sequence();
3782
3783     trace("creating maximized visible MDI child window 2(Switch test)\n");
3784     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3785                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3786                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3787                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3788     assert(mdi_child2);
3789     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3790
3791     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3792     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3793
3794     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3795     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3796
3797     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3798     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3799     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3800     flush_sequence();
3801
3802     trace("Switch child window.\n");
3803     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3804     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3805     trace("end of test for switch maximized MDI children\n");
3806     flush_sequence();
3807
3808     /* Prepare for switching test of not maximized MDI children  */
3809     ShowWindow( mdi_child, SW_NORMAL );
3810     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3811     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3812     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3813     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3814     flush_sequence();
3815
3816     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3817     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3818     trace("end of test for switch not maximized MDI children\n");
3819     flush_sequence();
3820
3821     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3822     flush_sequence();
3823
3824     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3825     flush_sequence();
3826
3827     SetFocus(0);
3828     flush_sequence();
3829     /* end of tests for switch maximized/not maximized MDI children */
3830
3831     mdi_cs.szClass = "MDI_child_Class";
3832     mdi_cs.szTitle = "MDI child";
3833     mdi_cs.hOwner = GetModuleHandleA(0);
3834     mdi_cs.x = 0;
3835     mdi_cs.y = 0;
3836     mdi_cs.cx = CW_USEDEFAULT;
3837     mdi_cs.cy = CW_USEDEFAULT;
3838     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3839     mdi_cs.lParam = 0;
3840     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3841     ok(mdi_child != 0, "MDI child creation failed\n");
3842     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3843
3844     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3845
3846     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3847     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3848
3849     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3850     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3851     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3852
3853     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3854     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3855     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3856     flush_sequence();
3857
3858     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3859     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3860
3861     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3862     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3863     ok(!active_child, "wrong active MDI child %p\n", active_child);
3864
3865     SetFocus(0);
3866     flush_sequence();
3867
3868     DestroyWindow(mdi_client);
3869     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3870
3871     /* test maximization of MDI child with invisible parent */
3872     client_cs.hWindowMenu = 0;
3873     mdi_client = CreateWindow("MDI_client_class",
3874                                  NULL,
3875                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3876                                  0, 0, 660, 430,
3877                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3878     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3879
3880     ShowWindow(mdi_client, SW_HIDE);
3881     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3882
3883     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3884                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3885                                 0, 0, 650, 440,
3886                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3887     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3888
3889     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3890     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3891     zoomed = IsZoomed(mdi_child);
3892     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3893     
3894     ShowWindow(mdi_client, SW_SHOW);
3895     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3896
3897     DestroyWindow(mdi_child);
3898     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3899
3900     /* end of test for maximization of MDI child with invisible parent */
3901
3902     DestroyWindow(mdi_client);
3903     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3904
3905     DestroyWindow(mdi_frame);
3906     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3907 }
3908 /************************* End of MDI test **********************************/
3909
3910 static void test_WM_SETREDRAW(HWND hwnd)
3911 {
3912     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3913
3914     flush_events();
3915     flush_sequence();
3916
3917     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3918     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3919
3920     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3921     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3922
3923     flush_sequence();
3924     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3925     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3926
3927     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3928     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3929
3930     /* restore original WS_VISIBLE state */
3931     SetWindowLongA(hwnd, GWL_STYLE, style);
3932
3933     flush_events();
3934     flush_sequence();
3935 }
3936
3937 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3938 {
3939     struct recvd_message msg;
3940
3941     if (ignore_message( message )) return 0;
3942
3943     switch (message)
3944     {
3945         /* ignore */
3946         case WM_MOUSEMOVE:
3947         case WM_NCMOUSEMOVE:
3948         case WM_NCMOUSELEAVE:
3949         case WM_SETCURSOR:
3950             return 0;
3951         case WM_NCHITTEST:
3952             return HTCLIENT;
3953     }
3954
3955     msg.hwnd = hwnd;
3956     msg.message = message;
3957     msg.flags = sent|wparam|lparam;
3958     msg.wParam = wParam;
3959     msg.lParam = lParam;
3960     msg.descr = "dialog";
3961     add_message(&msg);
3962
3963     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3964     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3965     return 0;
3966 }
3967
3968 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3969 {
3970     DWORD style, exstyle;
3971     INT xmin, xmax;
3972     BOOL ret;
3973
3974     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3975     style = GetWindowLongA(hwnd, GWL_STYLE);
3976     /* do not be confused by WS_DLGFRAME set */
3977     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3978
3979     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3980     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3981
3982     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3983     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3984     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3985         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3986     else
3987         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3988
3989     style = GetWindowLongA(hwnd, GWL_STYLE);
3990     if (set) ok(style & set, "style %08x should be set\n", set);
3991     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3992
3993     /* a subsequent call should do nothing */
3994     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3995     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3996     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3997
3998     xmin = 0xdeadbeef;
3999     xmax = 0xdeadbeef;
4000     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4001     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4002     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4003     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4004     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4005 }
4006
4007 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4008 {
4009     DWORD style, exstyle;
4010     SCROLLINFO si;
4011     BOOL ret;
4012
4013     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4014     style = GetWindowLongA(hwnd, GWL_STYLE);
4015     /* do not be confused by WS_DLGFRAME set */
4016     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4017
4018     if (clear) ok(style & clear, "style %08x should be set\n", clear);
4019     if (set) ok(!(style & set), "style %08x should not be set\n", set);
4020
4021     si.cbSize = sizeof(si);
4022     si.fMask = SIF_RANGE;
4023     si.nMin = min;
4024     si.nMax = max;
4025     SetScrollInfo(hwnd, ctl, &si, TRUE);
4026     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4027         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4028     else
4029         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4030
4031     style = GetWindowLongA(hwnd, GWL_STYLE);
4032     if (set) ok(style & set, "style %08x should be set\n", set);
4033     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4034
4035     /* a subsequent call should do nothing */
4036     SetScrollInfo(hwnd, ctl, &si, TRUE);
4037     if (style & WS_HSCROLL)
4038         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4039     else if (style & WS_VSCROLL)
4040         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4041     else
4042         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4043
4044     si.fMask = SIF_PAGE;
4045     si.nPage = 5;
4046     SetScrollInfo(hwnd, ctl, &si, FALSE);
4047     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4048
4049     si.fMask = SIF_POS;
4050     si.nPos = max - 1;
4051     SetScrollInfo(hwnd, ctl, &si, FALSE);
4052     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4053
4054     si.fMask = SIF_RANGE;
4055     si.nMin = 0xdeadbeef;
4056     si.nMax = 0xdeadbeef;
4057     ret = GetScrollInfo(hwnd, ctl, &si);
4058     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4059     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4060     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4061     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4062 }
4063
4064 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4065 static void test_scroll_messages(HWND hwnd)
4066 {
4067     SCROLLINFO si;
4068     INT min, max;
4069     BOOL ret;
4070
4071     flush_events();
4072     flush_sequence();
4073
4074     min = 0xdeadbeef;
4075     max = 0xdeadbeef;
4076     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4077     ok( ret, "GetScrollRange error %d\n", GetLastError());
4078     if (sequence->message != WmGetScrollRangeSeq[0].message)
4079         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4080     /* values of min and max are undefined */
4081     flush_sequence();
4082
4083     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4084     ok( ret, "SetScrollRange error %d\n", GetLastError());
4085     if (sequence->message != WmSetScrollRangeSeq[0].message)
4086         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4087     flush_sequence();
4088
4089     min = 0xdeadbeef;
4090     max = 0xdeadbeef;
4091     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4092     ok( ret, "GetScrollRange error %d\n", GetLastError());
4093     if (sequence->message != WmGetScrollRangeSeq[0].message)
4094         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4095     /* values of min and max are undefined */
4096     flush_sequence();
4097
4098     si.cbSize = sizeof(si);
4099     si.fMask = SIF_RANGE;
4100     si.nMin = 20;
4101     si.nMax = 160;
4102     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4103     if (sequence->message != WmSetScrollRangeSeq[0].message)
4104         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4105     flush_sequence();
4106
4107     si.fMask = SIF_PAGE;
4108     si.nPage = 10;
4109     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4110     if (sequence->message != WmSetScrollRangeSeq[0].message)
4111         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4112     flush_sequence();
4113
4114     si.fMask = SIF_POS;
4115     si.nPos = 20;
4116     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4117     if (sequence->message != WmSetScrollRangeSeq[0].message)
4118         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4119     flush_sequence();
4120
4121     si.fMask = SIF_RANGE;
4122     si.nMin = 0xdeadbeef;
4123     si.nMax = 0xdeadbeef;
4124     ret = GetScrollInfo(hwnd, SB_CTL, &si);
4125     ok( ret, "GetScrollInfo error %d\n", GetLastError());
4126     if (sequence->message != WmGetScrollInfoSeq[0].message)
4127         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4128     /* values of min and max are undefined */
4129     flush_sequence();
4130
4131     /* set WS_HSCROLL */
4132     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4133     /* clear WS_HSCROLL */
4134     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4135
4136     /* set WS_HSCROLL */
4137     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4138     /* clear WS_HSCROLL */
4139     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4140
4141     /* set WS_VSCROLL */
4142     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4143     /* clear WS_VSCROLL */
4144     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4145
4146     /* set WS_VSCROLL */
4147     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4148     /* clear WS_VSCROLL */
4149     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4150 }
4151
4152 static void test_showwindow(void)
4153 {
4154     HWND hwnd, hchild;
4155     RECT rc;
4156
4157     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4158                            100, 100, 200, 200, 0, 0, 0, NULL);
4159     ok (hwnd != 0, "Failed to create overlapped window\n");
4160     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4161                              0, 0, 10, 10, hwnd, 0, 0, NULL);
4162     ok (hchild != 0, "Failed to create child\n");
4163     flush_sequence();
4164
4165     /* ShowWindow( SW_SHOWNA) for invisible top level window */
4166     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4167     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4168     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4169
4170     /* ShowWindow( SW_SHOWNA) for now visible top level window */
4171     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4172     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4173     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4174     /* back to invisible */
4175     ShowWindow(hchild, SW_HIDE);
4176     ShowWindow(hwnd, SW_HIDE);
4177     flush_sequence();
4178     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
4179     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4180     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4181     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4182     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
4183     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4184     flush_sequence();
4185     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4186     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4187     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4188     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4189     ShowWindow( hwnd, SW_SHOW);
4190     flush_sequence();
4191     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4192     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4193     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4194
4195     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4196     ShowWindow( hchild, SW_HIDE);
4197     flush_sequence();
4198     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4199     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4200     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4201
4202     SetCapture(hchild);
4203     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4204     DestroyWindow(hchild);
4205     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4206
4207     DestroyWindow(hwnd);
4208     flush_sequence();
4209
4210     /* Popup windows */
4211     /* Test 1:
4212      * 1. Create invisible maximized popup window.
4213      * 2. Move and resize it.
4214      * 3. Show it maximized.
4215      */
4216     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4217     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4218                            100, 100, 200, 200, 0, 0, 0, NULL);
4219     ok (hwnd != 0, "Failed to create popup window\n");
4220     ok(IsZoomed(hwnd), "window should be maximized\n");
4221     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4222
4223     GetWindowRect(hwnd, &rc);
4224     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4225         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4226         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
4227         rc.left, rc.top, rc.right, rc.bottom);
4228     /* Reset window's size & position */
4229     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4230     ok(IsZoomed(hwnd), "window should be maximized\n");
4231     flush_sequence();
4232
4233     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4234     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4235     ok(IsZoomed(hwnd), "window should be maximized\n");
4236     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4237
4238     GetWindowRect(hwnd, &rc);
4239     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4240         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4241         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
4242         rc.left, rc.top, rc.right, rc.bottom);
4243     DestroyWindow(hwnd);
4244     flush_sequence();
4245
4246     /* Test 2:
4247      * 1. Create invisible maximized popup window.
4248      * 2. Show it maximized.
4249      */
4250     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4251     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4252                            100, 100, 200, 200, 0, 0, 0, NULL);
4253     ok (hwnd != 0, "Failed to create popup window\n");
4254     ok(IsZoomed(hwnd), "window should be maximized\n");
4255     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4256
4257     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4258     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4259     ok(IsZoomed(hwnd), "window should be maximized\n");
4260     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4261     DestroyWindow(hwnd);
4262     flush_sequence();
4263
4264     /* Test 3:
4265      * 1. Create visible maximized popup window.
4266      */
4267     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4268     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4269                            100, 100, 200, 200, 0, 0, 0, NULL);
4270     ok (hwnd != 0, "Failed to create popup window\n");
4271     ok(IsZoomed(hwnd), "window should be maximized\n");
4272     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4273     DestroyWindow(hwnd);
4274     flush_sequence();
4275
4276     /* Test 4:
4277      * 1. Create visible popup window.
4278      * 2. Maximize it.
4279      */
4280     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4281     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4282                            100, 100, 200, 200, 0, 0, 0, NULL);
4283     ok (hwnd != 0, "Failed to create popup window\n");
4284     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4285     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4286
4287     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4288     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4289     ok(IsZoomed(hwnd), "window should be maximized\n");
4290     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4291     DestroyWindow(hwnd);
4292     flush_sequence();
4293 }
4294
4295 static void test_sys_menu(void)
4296 {
4297     HWND hwnd;
4298     HMENU hmenu;
4299     UINT state;
4300
4301     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4302                            100, 100, 200, 200, 0, 0, 0, NULL);
4303     ok (hwnd != 0, "Failed to create overlapped window\n");
4304
4305     flush_sequence();
4306
4307     /* test existing window without CS_NOCLOSE style */
4308     hmenu = GetSystemMenu(hwnd, FALSE);
4309     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4310
4311     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4312     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4313     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4314
4315     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4316     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4317
4318     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4319     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4320     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4321
4322     EnableMenuItem(hmenu, SC_CLOSE, 0);
4323     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4324
4325     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4326     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4327     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4328
4329     /* test whether removing WS_SYSMENU destroys a system menu */
4330     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4331     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4332     flush_sequence();
4333     hmenu = GetSystemMenu(hwnd, FALSE);
4334     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4335
4336     DestroyWindow(hwnd);
4337
4338     /* test new window with CS_NOCLOSE style */
4339     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4340                            100, 100, 200, 200, 0, 0, 0, NULL);
4341     ok (hwnd != 0, "Failed to create overlapped window\n");
4342
4343     hmenu = GetSystemMenu(hwnd, FALSE);
4344     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4345
4346     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4347     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4348
4349     DestroyWindow(hwnd);
4350
4351     /* test new window without WS_SYSMENU style */
4352     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4353                            100, 100, 200, 200, 0, 0, 0, NULL);
4354     ok(hwnd != 0, "Failed to create overlapped window\n");
4355
4356     hmenu = GetSystemMenu(hwnd, FALSE);
4357     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4358
4359     DestroyWindow(hwnd);
4360 }
4361
4362 /* For shown WS_OVERLAPPEDWINDOW */
4363 static const struct message WmSetIcon_1[] = {
4364     { WM_SETICON, sent },
4365     { 0x00AE, sent|defwinproc|optional }, /* XP */
4366     { WM_GETTEXT, sent|defwinproc|optional },
4367     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4368     { 0 }
4369 };
4370
4371 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4372 static const struct message WmSetIcon_2[] = {
4373     { WM_SETICON, sent },
4374     { 0 }
4375 };
4376
4377 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4378 static const struct message WmInitEndSession[] = {
4379     { 0x003B, sent },
4380     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4381     { 0 }
4382 };
4383
4384 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4385 static const struct message WmInitEndSession_2[] = {
4386     { 0x003B, sent },
4387     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4388     { 0 }
4389 };
4390
4391 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4392 static const struct message WmInitEndSession_3[] = {
4393     { 0x003B, sent },
4394     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4395     { 0 }
4396 };
4397
4398 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4399 static const struct message WmInitEndSession_4[] = {
4400     { 0x003B, sent },
4401     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4402     { 0 }
4403 };
4404
4405 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4406 static const struct message WmInitEndSession_5[] = {
4407     { 0x003B, sent },
4408     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4409     { 0 }
4410 };
4411
4412 static const struct message WmOptionalPaint[] = {
4413     { WM_PAINT, sent|optional },
4414     { WM_NCPAINT, sent|beginpaint|optional },
4415     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4416     { WM_ERASEBKGND, sent|beginpaint|optional },
4417     { 0 }
4418 };
4419
4420 static const struct message WmZOrder[] = {
4421     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4422     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4423     { HCBT_ACTIVATE, hook },
4424     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4425     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4426     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4427     { WM_GETTEXT, sent|optional },
4428     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4429     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4430     { WM_NCACTIVATE, sent|lparam, 1, 0 },
4431     { WM_GETTEXT, sent|defwinproc|optional },
4432     { WM_GETTEXT, sent|defwinproc|optional },
4433     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4434     { HCBT_SETFOCUS, hook },
4435     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4436     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4437     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4438     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4439     { WM_GETTEXT, sent|optional },
4440     { WM_NCCALCSIZE, sent|optional },
4441     { 0 }
4442 };
4443
4444 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4445 {
4446     DWORD ret;
4447     MSG msg;
4448
4449     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4450     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4451
4452     PostMessageA(hwnd, WM_USER, 0, 0);
4453
4454     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4455     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4456
4457     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4458     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4459
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     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4466     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4467
4468     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4469     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4470
4471     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4472     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4473     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4474
4475     PostMessageA(hwnd, WM_USER, 0, 0);
4476
4477     /* new incoming message causes it to become signaled again */
4478     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4479     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4480
4481     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4482     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4483     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4484     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4485 }
4486
4487 /* test if we receive the right sequence of messages */
4488 static void test_messages(void)
4489 {
4490     HWND hwnd, hparent, hchild;
4491     HWND hchild2, hbutton;
4492     HMENU hmenu;
4493     MSG msg;
4494     LRESULT res;
4495
4496     flush_sequence();
4497
4498     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4499                            100, 100, 200, 200, 0, 0, 0, NULL);
4500     ok (hwnd != 0, "Failed to create overlapped window\n");
4501     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4502
4503     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4504     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4505     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4506
4507     /* test WM_SETREDRAW on a not visible top level window */
4508     test_WM_SETREDRAW(hwnd);
4509
4510     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4511     flush_events();
4512     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4513     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4514
4515     ok(GetActiveWindow() == hwnd, "window should be active\n");
4516     ok(GetFocus() == hwnd, "window should have input focus\n");
4517     ShowWindow(hwnd, SW_HIDE);
4518     flush_events();
4519     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4520
4521     ShowWindow(hwnd, SW_SHOW);
4522     flush_events();
4523     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4524
4525     ShowWindow(hwnd, SW_HIDE);
4526     flush_events();
4527     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4528
4529     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4530     flush_events();
4531     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4532     flush_sequence();
4533
4534     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
4535     {
4536         ShowWindow(hwnd, SW_RESTORE);
4537         flush_events();
4538         ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4539         flush_sequence();
4540     }
4541
4542     ShowWindow(hwnd, SW_MINIMIZE);
4543     flush_events();
4544     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4545     flush_sequence();
4546
4547     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
4548     {
4549         ShowWindow(hwnd, SW_RESTORE);
4550         flush_events();
4551         ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4552         flush_sequence();
4553     }
4554
4555     ShowWindow(hwnd, SW_SHOW);
4556     flush_events();
4557     ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4558
4559     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4560     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4561     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4562     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4563
4564     /* test WM_SETREDRAW on a visible top level window */
4565     ShowWindow(hwnd, SW_SHOW);
4566     flush_events();
4567     test_WM_SETREDRAW(hwnd);
4568
4569     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4570     test_scroll_messages(hwnd);
4571
4572     /* test resizing and moving */
4573     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4574     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4575     flush_events();
4576     flush_sequence();
4577     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4578     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4579     flush_events();
4580     flush_sequence();
4581     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4582     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4583     flush_events();
4584     flush_sequence();
4585
4586     /* popups don't get WM_GETMINMAXINFO */
4587     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4588     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4589     flush_sequence();
4590     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4591     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4592
4593     DestroyWindow(hwnd);
4594     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4595
4596     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4597                               100, 100, 200, 200, 0, 0, 0, NULL);
4598     ok (hparent != 0, "Failed to create parent window\n");
4599     flush_sequence();
4600
4601     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4602                              0, 0, 10, 10, hparent, 0, 0, NULL);
4603     ok (hchild != 0, "Failed to create child window\n");
4604     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4605     DestroyWindow(hchild);
4606     flush_sequence();
4607
4608     /* visible child window with a caption */
4609     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4610                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4611                              0, 0, 10, 10, hparent, 0, 0, NULL);
4612     ok (hchild != 0, "Failed to create child window\n");
4613     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4614
4615     trace("testing scroll APIs on a visible child window %p\n", hchild);
4616     test_scroll_messages(hchild);
4617
4618     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4619     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4620
4621     DestroyWindow(hchild);
4622     flush_sequence();
4623
4624     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4625                              0, 0, 10, 10, hparent, 0, 0, NULL);
4626     ok (hchild != 0, "Failed to create child window\n");
4627     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4628     
4629     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4630                                100, 100, 50, 50, hparent, 0, 0, NULL);
4631     ok (hchild2 != 0, "Failed to create child2 window\n");
4632     flush_sequence();
4633
4634     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4635                               0, 100, 50, 50, hchild, 0, 0, NULL);
4636     ok (hbutton != 0, "Failed to create button window\n");
4637
4638     /* test WM_SETREDRAW on a not visible child window */
4639     test_WM_SETREDRAW(hchild);
4640
4641     ShowWindow(hchild, SW_SHOW);
4642     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4643
4644     /* check parent messages too */
4645     log_all_parent_messages++;
4646     ShowWindow(hchild, SW_HIDE);
4647     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4648     log_all_parent_messages--;
4649
4650     ShowWindow(hchild, SW_SHOW);
4651     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4652
4653     ShowWindow(hchild, SW_HIDE);
4654     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4655
4656     ShowWindow(hchild, SW_SHOW);
4657     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4658
4659     /* test WM_SETREDRAW on a visible child window */
4660     test_WM_SETREDRAW(hchild);
4661
4662     log_all_parent_messages++;
4663     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4664     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4665     log_all_parent_messages--;
4666
4667     ShowWindow(hchild, SW_HIDE);
4668     flush_sequence();
4669     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4670     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4671
4672     ShowWindow(hchild, SW_HIDE);
4673     flush_sequence();
4674     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4675     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4676
4677     /* DestroyWindow sequence below expects that a child has focus */
4678     SetFocus(hchild);
4679     flush_sequence();
4680
4681     DestroyWindow(hchild);
4682     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4683     DestroyWindow(hchild2);
4684     DestroyWindow(hbutton);
4685
4686     flush_sequence();
4687     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4688                              0, 0, 100, 100, hparent, 0, 0, NULL);
4689     ok (hchild != 0, "Failed to create child popup window\n");
4690     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4691     DestroyWindow(hchild);
4692
4693     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4694     flush_sequence();
4695     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4696                              0, 0, 100, 100, hparent, 0, 0, NULL);
4697     ok (hchild != 0, "Failed to create popup window\n");
4698     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4699     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4700     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4701     flush_sequence();
4702     ShowWindow(hchild, SW_SHOW);
4703     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4704     flush_sequence();
4705     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4706     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4707     flush_sequence();
4708     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4709     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4710     DestroyWindow(hchild);
4711
4712     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4713      * changes nothing in message sequences.
4714      */
4715     flush_sequence();
4716     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4717                              0, 0, 100, 100, hparent, 0, 0, NULL);
4718     ok (hchild != 0, "Failed to create popup window\n");
4719     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4720     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4721     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4722     flush_sequence();
4723     ShowWindow(hchild, SW_SHOW);
4724     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4725     flush_sequence();
4726     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4727     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4728     DestroyWindow(hchild);
4729
4730     flush_sequence();
4731     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4732                            0, 0, 100, 100, hparent, 0, 0, NULL);
4733     ok(hwnd != 0, "Failed to create custom dialog window\n");
4734     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4735
4736     if(0) {
4737     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4738     test_scroll_messages(hwnd);
4739     }
4740
4741     flush_sequence();
4742
4743     test_def_id = 1;
4744     SendMessage(hwnd, WM_NULL, 0, 0);
4745
4746     flush_sequence();
4747     after_end_dialog = 1;
4748     EndDialog( hwnd, 0 );
4749     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4750
4751     DestroyWindow(hwnd);
4752     after_end_dialog = 0;
4753     test_def_id = 0;
4754
4755     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4756                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4757     ok(hwnd != 0, "Failed to create custom dialog window\n");
4758     flush_sequence();
4759     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4760     ShowWindow(hwnd, SW_SHOW);
4761     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4762     DestroyWindow(hwnd);
4763
4764     flush_sequence();
4765     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4766     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4767
4768     DestroyWindow(hparent);
4769     flush_sequence();
4770
4771     /* Message sequence for SetMenu */
4772     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4773     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4774
4775     hmenu = CreateMenu();
4776     ok (hmenu != 0, "Failed to create menu\n");
4777     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4778     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4779                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4780     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4781     ok (SetMenu(hwnd, 0), "SetMenu\n");
4782     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4783     ok (SetMenu(hwnd, 0), "SetMenu\n");
4784     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4785     ShowWindow(hwnd, SW_SHOW);
4786     UpdateWindow( hwnd );
4787     flush_events();
4788     flush_sequence();
4789     ok (SetMenu(hwnd, 0), "SetMenu\n");
4790     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4791     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4792     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4793
4794     UpdateWindow( hwnd );
4795     flush_events();
4796     flush_sequence();
4797     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4798     flush_events();
4799     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4800
4801     DestroyWindow(hwnd);
4802     flush_sequence();
4803
4804     /* Message sequence for EnableWindow */
4805     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4806                               100, 100, 200, 200, 0, 0, 0, NULL);
4807     ok (hparent != 0, "Failed to create parent window\n");
4808     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4809                              0, 0, 10, 10, hparent, 0, 0, NULL);
4810     ok (hchild != 0, "Failed to create child window\n");
4811
4812     SetFocus(hchild);
4813     flush_events();
4814     flush_sequence();
4815
4816     EnableWindow(hparent, FALSE);
4817     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4818
4819     EnableWindow(hparent, TRUE);
4820     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4821
4822     flush_events();
4823     flush_sequence();
4824
4825     test_MsgWaitForMultipleObjects(hparent);
4826
4827     /* the following test causes an exception in user.exe under win9x */
4828     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4829     {
4830         DestroyWindow(hparent);
4831         flush_sequence();
4832         return;
4833     }
4834     PostMessageW( hparent, WM_USER+1, 0, 0 );
4835     /* PeekMessage(NULL) fails, but still removes the message */
4836     SetLastError(0xdeadbeef);
4837     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4838     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4839         GetLastError() == 0xdeadbeef, /* NT4 */
4840         "last error is %d\n", GetLastError() );
4841     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4842     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4843
4844     DestroyWindow(hchild);
4845     DestroyWindow(hparent);
4846     flush_sequence();
4847
4848     /* Message sequences for WM_SETICON */
4849     trace("testing WM_SETICON\n");
4850     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4851                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4852                            NULL, NULL, 0);
4853     ShowWindow(hwnd, SW_SHOW);
4854     UpdateWindow(hwnd);
4855     flush_events();
4856     flush_sequence();
4857     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4858     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4859
4860     ShowWindow(hwnd, SW_HIDE);
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 hidden window with caption", FALSE);
4865     DestroyWindow(hwnd);
4866     flush_sequence();
4867
4868     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4869                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4870                            NULL, NULL, 0);
4871     ShowWindow(hwnd, SW_SHOW);
4872     UpdateWindow(hwnd);
4873     flush_events();
4874     flush_sequence();
4875     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4876     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4877
4878     ShowWindow(hwnd, SW_HIDE);
4879     flush_events();
4880     flush_sequence();
4881     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4882     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4883
4884     flush_sequence();
4885     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4886     if (!res)
4887     {
4888         todo_wine win_skip( "Message 0x3b not supported\n" );
4889         goto done;
4890     }
4891     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4892     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4893     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4894     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4895     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4896     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4897     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4898     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4899
4900     flush_sequence();
4901     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4902     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4903     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4904     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4905     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4906     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4907
4908     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4909     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4910     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4911
4912     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4913     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4914     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4915
4916 done:
4917     DestroyWindow(hwnd);
4918     flush_sequence();
4919 }
4920
4921 static void test_setwindowpos(void)
4922 {
4923     HWND hwnd;
4924     RECT rc;
4925     LRESULT res;
4926     const INT winX = 100;
4927     const INT winY = 100;
4928     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4929
4930     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4931                            0, 0, winX, winY, 0,
4932                            NULL, NULL, 0);
4933
4934     GetWindowRect(hwnd, &rc);
4935     expect(sysX, rc.right);
4936     expect(winY, rc.bottom);
4937
4938     flush_events();
4939     flush_sequence();
4940     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4941     ok_sequence(WmZOrder, "Z-Order", TRUE);
4942     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4943
4944     GetWindowRect(hwnd, &rc);
4945     expect(sysX, rc.right);
4946     expect(winY, rc.bottom);
4947     DestroyWindow(hwnd);
4948 }
4949
4950 static void invisible_parent_tests(void)
4951 {
4952     HWND hparent, hchild;
4953
4954     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4955                               100, 100, 200, 200, 0, 0, 0, NULL);
4956     ok (hparent != 0, "Failed to create parent window\n");
4957     flush_sequence();
4958
4959     /* test showing child with hidden parent */
4960
4961     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4962                              0, 0, 10, 10, hparent, 0, 0, NULL);
4963     ok (hchild != 0, "Failed to create child window\n");
4964     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4965
4966     ShowWindow( hchild, SW_MINIMIZE );
4967     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4968     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4969     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4970
4971     /* repeat */
4972     flush_events();
4973     flush_sequence();
4974     ShowWindow( hchild, SW_MINIMIZE );
4975     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4976
4977     DestroyWindow(hchild);
4978     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4979                              0, 0, 10, 10, hparent, 0, 0, NULL);
4980     flush_sequence();
4981
4982     ShowWindow( hchild, SW_MAXIMIZE );
4983     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4984     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4985     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4986
4987     /* repeat */
4988     flush_events();
4989     flush_sequence();
4990     ShowWindow( hchild, SW_MAXIMIZE );
4991     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4992
4993     DestroyWindow(hchild);
4994     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4995                              0, 0, 10, 10, hparent, 0, 0, NULL);
4996     flush_sequence();
4997
4998     ShowWindow( hchild, SW_RESTORE );
4999     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5000     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5001     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5002
5003     DestroyWindow(hchild);
5004     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5005                              0, 0, 10, 10, hparent, 0, 0, NULL);
5006     flush_sequence();
5007
5008     ShowWindow( hchild, SW_SHOWMINIMIZED );
5009     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5010     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5011     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5012
5013     /* repeat */
5014     flush_events();
5015     flush_sequence();
5016     ShowWindow( hchild, SW_SHOWMINIMIZED );
5017     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5018
5019     DestroyWindow(hchild);
5020     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5021                              0, 0, 10, 10, hparent, 0, 0, NULL);
5022     flush_sequence();
5023
5024     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5025     ShowWindow( hchild, SW_SHOWMAXIMIZED );
5026     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5027     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5028     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5029
5030     DestroyWindow(hchild);
5031     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5032                              0, 0, 10, 10, hparent, 0, 0, NULL);
5033     flush_sequence();
5034
5035     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5036     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5037     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5038     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5039
5040     /* repeat */
5041     flush_events();
5042     flush_sequence();
5043     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5044     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5045
5046     DestroyWindow(hchild);
5047     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5048                              0, 0, 10, 10, hparent, 0, 0, NULL);
5049     flush_sequence();
5050
5051     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5052     ShowWindow( hchild, SW_FORCEMINIMIZE );
5053     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5054 todo_wine {
5055     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5056 }
5057     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5058
5059     DestroyWindow(hchild);
5060     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5061                              0, 0, 10, 10, hparent, 0, 0, NULL);
5062     flush_sequence();
5063
5064     ShowWindow( hchild, SW_SHOWNA );
5065     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5066     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5067     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5068
5069     /* repeat */
5070     flush_events();
5071     flush_sequence();
5072     ShowWindow( hchild, SW_SHOWNA );
5073     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5074
5075     DestroyWindow(hchild);
5076     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5077                              0, 0, 10, 10, hparent, 0, 0, NULL);
5078     flush_sequence();
5079
5080     ShowWindow( hchild, SW_SHOW );
5081     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5082     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5083     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5084
5085     /* repeat */
5086     flush_events();
5087     flush_sequence();
5088     ShowWindow( hchild, SW_SHOW );
5089     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5090
5091     ShowWindow( hchild, SW_HIDE );
5092     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5093     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5094     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5095
5096     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5097     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5098     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5099     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5100
5101     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5102     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5103     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5104     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5105
5106     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5107     flush_sequence();
5108     DestroyWindow(hchild);
5109     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5110
5111     DestroyWindow(hparent);
5112     flush_sequence();
5113 }
5114
5115 /****************** button message test *************************/
5116 #define ID_BUTTON 0x000e
5117
5118 static const struct message WmSetFocusButtonSeq[] =
5119 {
5120     { HCBT_SETFOCUS, hook },
5121     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5122     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5123     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5124     { WM_SETFOCUS, sent|wparam, 0 },
5125     { WM_CTLCOLORBTN, sent|parent },
5126     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5127     { WM_APP, sent|wparam|lparam, 0, 0 },
5128     { 0 }
5129 };
5130 static const struct message WmKillFocusButtonSeq[] =
5131 {
5132     { HCBT_SETFOCUS, hook },
5133     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5134     { WM_KILLFOCUS, sent|wparam, 0 },
5135     { WM_CTLCOLORBTN, sent|parent },
5136     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5137     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5138     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5139     { WM_APP, sent|wparam|lparam, 0, 0 },
5140     { WM_PAINT, sent },
5141     { WM_CTLCOLORBTN, sent|parent },
5142     { 0 }
5143 };
5144 static const struct message WmSetFocusStaticSeq[] =
5145 {
5146     { HCBT_SETFOCUS, hook },
5147     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5148     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5149     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5150     { WM_SETFOCUS, sent|wparam, 0 },
5151     { WM_CTLCOLORSTATIC, sent|parent },
5152     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5153     { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5154     { WM_APP, sent|wparam|lparam, 0, 0 },
5155     { 0 }
5156 };
5157 static const struct message WmKillFocusStaticSeq[] =
5158 {
5159     { HCBT_SETFOCUS, hook },
5160     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5161     { WM_KILLFOCUS, sent|wparam, 0 },
5162     { WM_CTLCOLORSTATIC, sent|parent },
5163     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5164     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5165     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5166     { WM_APP, sent|wparam|lparam, 0, 0 },
5167     { WM_PAINT, sent },
5168     { WM_CTLCOLORSTATIC, sent|parent },
5169     { 0 }
5170 };
5171 static const struct message WmSetFocusOwnerdrawSeq[] =
5172 {
5173     { HCBT_SETFOCUS, hook },
5174     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5175     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5176     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5177     { WM_SETFOCUS, sent|wparam, 0 },
5178     { WM_CTLCOLORBTN, sent|parent },
5179     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5180     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5181     { WM_APP, sent|wparam|lparam, 0, 0 },
5182     { 0 }
5183 };
5184 static const struct message WmKillFocusOwnerdrawSeq[] =
5185 {
5186     { HCBT_SETFOCUS, hook },
5187     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5188     { WM_KILLFOCUS, sent|wparam, 0 },
5189     { WM_CTLCOLORBTN, sent|parent },
5190     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5191     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5192     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5193     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5194     { WM_APP, sent|wparam|lparam, 0, 0 },
5195     { WM_PAINT, sent },
5196     { WM_CTLCOLORBTN, sent|parent },
5197     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5198     { 0 }
5199 };
5200 static const struct message WmLButtonDownSeq[] =
5201 {
5202     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5203     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5204     { HCBT_SETFOCUS, hook },
5205     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5206     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5207     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5208     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5209     { WM_CTLCOLORBTN, sent|defwinproc },
5210     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5211     { WM_CTLCOLORBTN, sent|defwinproc },
5212     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5213     { 0 }
5214 };
5215 static const struct message WmLButtonUpSeq[] =
5216 {
5217     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
5218     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
5219     { WM_CTLCOLORBTN, sent|defwinproc },
5220     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5221     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
5222     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
5223     { 0 }
5224 };
5225 static const struct message WmSetFontButtonSeq[] =
5226 {
5227     { WM_SETFONT, sent },
5228     { WM_PAINT, sent },
5229     { WM_ERASEBKGND, sent|defwinproc|optional },
5230     { WM_CTLCOLORBTN, sent|defwinproc },
5231     { 0 }
5232 };
5233 static const struct message WmSetStyleButtonSeq[] =
5234 {
5235     { BM_SETSTYLE, sent },
5236     { WM_APP, sent|wparam|lparam, 0, 0 },
5237     { WM_PAINT, sent },
5238     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5239     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5240     { WM_CTLCOLORBTN, sent|parent },
5241     { 0 }
5242 };
5243 static const struct message WmSetStyleStaticSeq[] =
5244 {
5245     { BM_SETSTYLE, sent },
5246     { WM_APP, sent|wparam|lparam, 0, 0 },
5247     { WM_PAINT, sent },
5248     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5249     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5250     { WM_CTLCOLORSTATIC, sent|parent },
5251     { 0 }
5252 };
5253 static const struct message WmSetStyleUserSeq[] =
5254 {
5255     { BM_SETSTYLE, sent },
5256     { WM_APP, sent|wparam|lparam, 0, 0 },
5257     { WM_PAINT, sent },
5258     { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
5259     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5260     { WM_CTLCOLORBTN, sent|parent },
5261     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
5262     { 0 }
5263 };
5264 static const struct message WmSetStyleOwnerdrawSeq[] =
5265 {
5266     { BM_SETSTYLE, sent },
5267     { WM_APP, sent|wparam|lparam, 0, 0 },
5268     { WM_PAINT, sent },
5269     { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
5270     { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
5271     { WM_CTLCOLORBTN, sent|parent },
5272     { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
5273     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5274     { 0 }
5275 };
5276 static const struct message WmSetStateButtonSeq[] =
5277 {
5278     { BM_SETSTATE, sent },
5279     { WM_CTLCOLORBTN, sent|parent },
5280     { WM_APP, sent|wparam|lparam, 0, 0 },
5281     { 0 }
5282 };
5283 static const struct message WmSetStateStaticSeq[] =
5284 {
5285     { BM_SETSTATE, sent },
5286     { WM_CTLCOLORSTATIC, sent|parent },
5287     { WM_APP, sent|wparam|lparam, 0, 0 },
5288     { 0 }
5289 };
5290 static const struct message WmSetStateUserSeq[] =
5291 {
5292     { BM_SETSTATE, sent },
5293     { WM_CTLCOLORBTN, sent|parent },
5294     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
5295     { WM_APP, sent|wparam|lparam, 0, 0 },
5296     { 0 }
5297 };
5298 static const struct message WmSetStateOwnerdrawSeq[] =
5299 {
5300     { BM_SETSTATE, sent },
5301     { WM_CTLCOLORBTN, sent|parent },
5302     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
5303     { WM_APP, sent|wparam|lparam, 0, 0 },
5304     { 0 }
5305 };
5306 static const struct message WmClearStateButtonSeq[] =
5307 {
5308     { BM_SETSTATE, sent },
5309     { WM_CTLCOLORBTN, sent|parent },
5310     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
5311     { WM_APP, sent|wparam|lparam, 0, 0 },
5312     { 0 }
5313 };
5314 static const struct message WmClearStateOwnerdrawSeq[] =
5315 {
5316     { BM_SETSTATE, sent },
5317     { WM_CTLCOLORBTN, sent|parent },
5318     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
5319     { WM_APP, sent|wparam|lparam, 0, 0 },
5320     { 0 }
5321 };
5322 static const struct message WmSetCheckIgnoredSeq[] =
5323 {
5324     { BM_SETCHECK, sent },
5325     { WM_APP, sent|wparam|lparam, 0, 0 },
5326     { 0 }
5327 };
5328 static const struct message WmSetCheckStaticSeq[] =
5329 {
5330     { BM_SETCHECK, sent },
5331     { WM_CTLCOLORSTATIC, sent|parent },
5332     { WM_APP, sent|wparam|lparam, 0, 0 },
5333     { 0 }
5334 };
5335
5336 static WNDPROC old_button_proc;
5337
5338 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5339 {
5340     static LONG defwndproc_counter = 0;
5341     LRESULT ret;
5342     struct recvd_message msg;
5343
5344     if (ignore_message( message )) return 0;
5345
5346     switch (message)
5347     {
5348     case WM_SYNCPAINT:
5349         break;
5350     case BM_SETSTATE:
5351         if (GetCapture())
5352             ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
5353         /* fall through */
5354     default:
5355         msg.hwnd = hwnd;
5356         msg.message = message;
5357         msg.flags = sent|wparam|lparam;
5358         if (defwndproc_counter) msg.flags |= defwinproc;
5359         msg.wParam = wParam;
5360         msg.lParam = lParam;
5361         msg.descr = "button";
5362         add_message(&msg);
5363     }
5364
5365     defwndproc_counter++;
5366     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
5367     defwndproc_counter--;
5368
5369     return ret;
5370 }
5371
5372 static void subclass_button(void)
5373 {
5374     WNDCLASSA cls;
5375
5376     if (!GetClassInfoA(0, "button", &cls)) assert(0);
5377
5378     old_button_proc = cls.lpfnWndProc;
5379
5380     cls.hInstance = GetModuleHandle(0);
5381     cls.lpfnWndProc = button_hook_proc;
5382     cls.lpszClassName = "my_button_class";
5383     UnregisterClass(cls.lpszClassName, cls.hInstance);
5384     if (!RegisterClassA(&cls)) assert(0);
5385 }
5386
5387 static void test_button_messages(void)
5388 {
5389     static const struct
5390     {
5391         DWORD style;
5392         DWORD dlg_code;
5393         const struct message *setfocus;
5394         const struct message *killfocus;
5395         const struct message *setstyle;
5396         const struct message *setstate;
5397         const struct message *clearstate;
5398         const struct message *setcheck;
5399     } button[] = {
5400         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5401           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5402           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5403         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
5404           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
5405           WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
5406         { BS_CHECKBOX, DLGC_BUTTON,
5407           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5408           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5409         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5410           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5411           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5412         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5413           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5414           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5415         { BS_3STATE, DLGC_BUTTON,
5416           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5417           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5418         { BS_AUTO3STATE, DLGC_BUTTON,
5419           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5420           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5421         { BS_GROUPBOX, DLGC_STATIC,
5422           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5423           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
5424         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5425           WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
5426           WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
5427         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5428           WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
5429           WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
5430         { BS_OWNERDRAW, DLGC_BUTTON,
5431           WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
5432           WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
5433     };
5434     unsigned int i;
5435     HWND hwnd, parent;
5436     DWORD dlg_code;
5437     HFONT zfont;
5438
5439     /* selection with VK_SPACE should capture button window */
5440     hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
5441                            0, 0, 50, 14, 0, 0, 0, NULL);
5442     ok(hwnd != 0, "Failed to create button window\n");
5443     ReleaseCapture();
5444     SetFocus(hwnd);
5445     SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
5446     ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
5447     SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
5448     DestroyWindow(hwnd);
5449
5450     subclass_button();
5451
5452     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5453                              100, 100, 200, 200, 0, 0, 0, NULL);
5454     ok(parent != 0, "Failed to create parent window\n");
5455
5456     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5457     {
5458         MSG msg;
5459         DWORD style, state;
5460
5461         trace("button style %08x\n", button[i].style);
5462
5463         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
5464                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
5465         ok(hwnd != 0, "Failed to create button window\n");
5466
5467         style = GetWindowLongA(hwnd, GWL_STYLE);
5468         style &= ~(WS_CHILD | BS_NOTIFY);
5469         /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
5470         if (button[i].style == BS_USERBUTTON)
5471             ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
5472         else
5473             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
5474
5475         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5476         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5477
5478         ShowWindow(hwnd, SW_SHOW);
5479         UpdateWindow(hwnd);
5480         SetFocus(0);
5481         flush_events();
5482         SetFocus(0);
5483         flush_sequence();
5484
5485         log_all_parent_messages++;
5486
5487         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5488         SetFocus(hwnd);
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].setfocus, "SetFocus(hwnd) on a button", FALSE);
5492
5493         SetFocus(0);
5494         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5495         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5496         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5497
5498         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
5499
5500         SendMessage(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
5501         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5502         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5503         ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
5504
5505         style = GetWindowLongA(hwnd, GWL_STYLE);
5506         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
5507         /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
5508         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5509
5510         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5511         ok(state == 0, "expected state 0, got %04x\n", state);
5512
5513         flush_sequence();
5514
5515         SendMessage(hwnd, BM_SETSTATE, TRUE, 0);
5516         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5517         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5518         ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
5519
5520         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5521         ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
5522
5523         style = GetWindowLongA(hwnd, GWL_STYLE);
5524         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5525         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5526
5527         flush_sequence();
5528
5529         SendMessage(hwnd, BM_SETSTATE, FALSE, 0);
5530         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5531         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5532         ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
5533
5534         state = SendMessage(hwnd, BM_GETSTATE, 0, 0);
5535         ok(state == 0, "expected state 0, got %04x\n", state);
5536
5537         style = GetWindowLongA(hwnd, GWL_STYLE);
5538         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5539         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5540
5541         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5542         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5543
5544         flush_sequence();
5545
5546         SendMessage(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
5547         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5548         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5549         ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
5550
5551         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5552         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
5553
5554         style = GetWindowLongA(hwnd, GWL_STYLE);
5555         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5556         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5557
5558         flush_sequence();
5559
5560         SendMessage(hwnd, BM_SETCHECK, BST_CHECKED, 0);
5561         SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */
5562         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
5563         ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
5564
5565         state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
5566         if (button[i].style == BS_PUSHBUTTON ||
5567             button[i].style == BS_DEFPUSHBUTTON ||
5568             button[i].style == BS_GROUPBOX ||
5569             button[i].style == BS_USERBUTTON ||
5570             button[i].style == BS_OWNERDRAW)
5571             ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
5572         else
5573             ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
5574
5575         style = GetWindowLongA(hwnd, GWL_STYLE);
5576         style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
5577         if (button[i].style == BS_RADIOBUTTON ||
5578             button[i].style == BS_AUTORADIOBUTTON)
5579             ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
5580         else
5581             ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
5582
5583         log_all_parent_messages--;
5584
5585         DestroyWindow(hwnd);
5586     }
5587
5588     DestroyWindow(parent);
5589
5590     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5591                            0, 0, 50, 14, 0, 0, 0, NULL);
5592     ok(hwnd != 0, "Failed to create button window\n");
5593
5594     SetForegroundWindow(hwnd);
5595     flush_events();
5596
5597     SetActiveWindow(hwnd);
5598     SetFocus(0);
5599     flush_sequence();
5600
5601     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5602     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5603
5604     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5605     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5606
5607     flush_sequence();
5608     zfont = GetStockObject(SYSTEM_FONT);
5609     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5610     UpdateWindow(hwnd);
5611     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5612
5613     DestroyWindow(hwnd);
5614 }
5615
5616 /****************** static message test *************************/
5617 static const struct message WmSetFontStaticSeq[] =
5618 {
5619     { WM_SETFONT, sent },
5620     { WM_PAINT, sent|defwinproc|optional },
5621     { WM_ERASEBKGND, sent|defwinproc|optional },
5622     { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
5623     { 0 }
5624 };
5625
5626 static WNDPROC old_static_proc;
5627
5628 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5629 {
5630     static LONG defwndproc_counter = 0;
5631     LRESULT ret;
5632     struct recvd_message msg;
5633
5634     if (ignore_message( message )) return 0;
5635
5636     msg.hwnd = hwnd;
5637     msg.message = message;
5638     msg.flags = sent|wparam|lparam;
5639     if (defwndproc_counter) msg.flags |= defwinproc;
5640     msg.wParam = wParam;
5641     msg.lParam = lParam;
5642     msg.descr = "static";
5643     add_message(&msg);
5644
5645     defwndproc_counter++;
5646     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5647     defwndproc_counter--;
5648
5649     return ret;
5650 }
5651
5652 static void subclass_static(void)
5653 {
5654     WNDCLASSA cls;
5655
5656     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5657
5658     old_static_proc = cls.lpfnWndProc;
5659
5660     cls.hInstance = GetModuleHandle(0);
5661     cls.lpfnWndProc = static_hook_proc;
5662     cls.lpszClassName = "my_static_class";
5663     UnregisterClass(cls.lpszClassName, cls.hInstance);
5664     if (!RegisterClassA(&cls)) assert(0);
5665 }
5666
5667 static void test_static_messages(void)
5668 {
5669     /* FIXME: make as comprehensive as the button message test */
5670     static const struct
5671     {
5672         DWORD style;
5673         DWORD dlg_code;
5674         const struct message *setfont;
5675     } static_ctrl[] = {
5676         { SS_LEFT, DLGC_STATIC,
5677           WmSetFontStaticSeq }
5678     };
5679     unsigned int i;
5680     HWND hwnd;
5681     DWORD dlg_code;
5682
5683     subclass_static();
5684
5685     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5686     {
5687         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5688                                0, 0, 50, 14, 0, 0, 0, NULL);
5689         ok(hwnd != 0, "Failed to create static window\n");
5690
5691         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5692         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5693
5694         ShowWindow(hwnd, SW_SHOW);
5695         UpdateWindow(hwnd);
5696         SetFocus(0);
5697         flush_sequence();
5698
5699         trace("static style %08x\n", static_ctrl[i].style);
5700         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5701         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5702
5703         DestroyWindow(hwnd);
5704     }
5705 }
5706
5707 /****************** ComboBox message test *************************/
5708 #define ID_COMBOBOX 0x000f
5709
5710 static const struct message WmKeyDownComboSeq[] =
5711 {
5712     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5713     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5714     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5715     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5716     { WM_CTLCOLOREDIT, sent|parent },
5717     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5718     { 0 }
5719 };
5720
5721 static WNDPROC old_combobox_proc;
5722
5723 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5724 {
5725     static LONG defwndproc_counter = 0;
5726     LRESULT ret;
5727     struct recvd_message msg;
5728
5729     /* do not log painting messages */
5730     if (message != WM_PAINT &&
5731         message != WM_NCPAINT &&
5732         message != WM_SYNCPAINT &&
5733         message != WM_ERASEBKGND &&
5734         message != WM_NCHITTEST &&
5735         message != WM_GETTEXT &&
5736         !ignore_message( message ))
5737     {
5738         msg.hwnd = hwnd;
5739         msg.message = message;
5740         msg.flags = sent|wparam|lparam;
5741         if (defwndproc_counter) msg.flags |= defwinproc;
5742         msg.wParam = wParam;
5743         msg.lParam = lParam;
5744         msg.descr = "combo";
5745         add_message(&msg);
5746     }
5747
5748     defwndproc_counter++;
5749     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5750     defwndproc_counter--;
5751
5752     return ret;
5753 }
5754
5755 static void subclass_combobox(void)
5756 {
5757     WNDCLASSA cls;
5758
5759     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5760
5761     old_combobox_proc = cls.lpfnWndProc;
5762
5763     cls.hInstance = GetModuleHandle(0);
5764     cls.lpfnWndProc = combobox_hook_proc;
5765     cls.lpszClassName = "my_combobox_class";
5766     UnregisterClass(cls.lpszClassName, cls.hInstance);
5767     if (!RegisterClassA(&cls)) assert(0);
5768 }
5769
5770 static void test_combobox_messages(void)
5771 {
5772     HWND parent, combo;
5773     LRESULT ret;
5774
5775     subclass_combobox();
5776
5777     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5778                              100, 100, 200, 200, 0, 0, 0, NULL);
5779     ok(parent != 0, "Failed to create parent window\n");
5780     flush_sequence();
5781
5782     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5783                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5784     ok(combo != 0, "Failed to create combobox window\n");
5785
5786     UpdateWindow(combo);
5787
5788     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5789     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5790
5791     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5792     ok(ret == 0, "expected 0, got %ld\n", ret);
5793     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5794     ok(ret == 1, "expected 1, got %ld\n", ret);
5795     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5796     ok(ret == 2, "expected 2, got %ld\n", ret);
5797
5798     SendMessage(combo, CB_SETCURSEL, 0, 0);
5799     SetFocus(combo);
5800     flush_sequence();
5801
5802     log_all_parent_messages++;
5803     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5804     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5805     log_all_parent_messages--;
5806     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5807
5808     DestroyWindow(combo);
5809     DestroyWindow(parent);
5810 }
5811
5812 /****************** WM_IME_KEYDOWN message test *******************/
5813
5814 static const struct message WmImeKeydownMsgSeq_0[] =
5815 {
5816     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5817     { WM_CHAR, wparam, 'A' },
5818     { 0 }
5819 };
5820
5821 static const struct message WmImeKeydownMsgSeq_1[] =
5822 {
5823     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5824     { WM_CHAR,    optional|wparam, VK_RETURN },
5825     { 0 }
5826 };
5827
5828 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5829 {
5830     struct recvd_message msg;
5831
5832     msg.hwnd = hwnd;
5833     msg.message = message;
5834     msg.flags = wparam|lparam;
5835     msg.wParam = wParam;
5836     msg.lParam = lParam;
5837     msg.descr = "wmime_keydown";
5838     add_message(&msg);
5839
5840     return DefWindowProcA(hwnd, message, wParam, lParam);
5841 }
5842
5843 static void register_wmime_keydown_class(void)
5844 {
5845     WNDCLASSA cls;
5846
5847     ZeroMemory(&cls, sizeof(WNDCLASSA));
5848     cls.lpfnWndProc = wmime_keydown_procA;
5849     cls.hInstance = GetModuleHandleA(0);
5850     cls.lpszClassName = "wmime_keydown_class";
5851     if (!RegisterClassA(&cls)) assert(0);
5852 }
5853
5854 static void test_wmime_keydown_message(void)
5855 {
5856     HWND hwnd;
5857     MSG msg;
5858
5859     trace("Message sequences by WM_IME_KEYDOWN\n");
5860
5861     register_wmime_keydown_class();
5862     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5863                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5864                            NULL, NULL, 0);
5865     flush_events();
5866     flush_sequence();
5867
5868     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5869     SendMessage(hwnd, WM_CHAR, 'A', 1);
5870     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5871
5872     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5873     {
5874         TranslateMessage(&msg);
5875         DispatchMessage(&msg);
5876     }
5877     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5878
5879     DestroyWindow(hwnd);
5880 }
5881
5882 /************* painting message test ********************/
5883
5884 void dump_region(HRGN hrgn)
5885 {
5886     DWORD i, size;
5887     RGNDATA *data = NULL;
5888     RECT *rect;
5889
5890     if (!hrgn)
5891     {
5892         printf( "null region\n" );
5893         return;
5894     }
5895     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5896     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5897     GetRegionData( hrgn, size, data );
5898     printf("%d rects:", data->rdh.nCount );
5899     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5900         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5901     printf("\n");
5902     HeapFree( GetProcessHeap(), 0, data );
5903 }
5904
5905 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5906 {
5907     INT ret;
5908     RECT r1, r2;
5909     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5910     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5911
5912     ret = GetUpdateRgn( hwnd, update, FALSE );
5913     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5914     if (ret == NULLREGION)
5915     {
5916         ok( !hrgn, "Update region shouldn't be empty\n" );
5917     }
5918     else
5919     {
5920         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5921         {
5922             ok( 0, "Regions are different\n" );
5923             if (winetest_debug > 0)
5924             {
5925                 printf( "Update region: " );
5926                 dump_region( update );
5927                 printf( "Wanted region: " );
5928                 dump_region( hrgn );
5929             }
5930         }
5931     }
5932     GetRgnBox( update, &r1 );
5933     GetUpdateRect( hwnd, &r2, FALSE );
5934     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5935         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5936         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5937
5938     DeleteObject( tmp );
5939     DeleteObject( update );
5940 }
5941
5942 static const struct message WmInvalidateRgn[] = {
5943     { WM_NCPAINT, sent },
5944     { WM_GETTEXT, sent|defwinproc|optional },
5945     { 0 }
5946 };
5947
5948 static const struct message WmGetUpdateRect[] = {
5949     { WM_NCPAINT, sent },
5950     { WM_GETTEXT, sent|defwinproc|optional },
5951     { WM_PAINT, sent },
5952     { 0 }
5953 };
5954
5955 static const struct message WmInvalidateFull[] = {
5956     { WM_NCPAINT, sent|wparam, 1 },
5957     { WM_GETTEXT, sent|defwinproc|optional },
5958     { 0 }
5959 };
5960
5961 static const struct message WmInvalidateErase[] = {
5962     { WM_NCPAINT, sent|wparam, 1 },
5963     { WM_GETTEXT, sent|defwinproc|optional },
5964     { WM_ERASEBKGND, sent },
5965     { 0 }
5966 };
5967
5968 static const struct message WmInvalidatePaint[] = {
5969     { WM_PAINT, sent },
5970     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5971     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5972     { 0 }
5973 };
5974
5975 static const struct message WmInvalidateErasePaint[] = {
5976     { WM_PAINT, sent },
5977     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5978     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5979     { WM_ERASEBKGND, sent|beginpaint|optional },
5980     { 0 }
5981 };
5982
5983 static const struct message WmInvalidateErasePaint2[] = {
5984     { WM_PAINT, sent },
5985     { WM_NCPAINT, sent|beginpaint },
5986     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5987     { WM_ERASEBKGND, sent|beginpaint|optional },
5988     { 0 }
5989 };
5990
5991 static const struct message WmErase[] = {
5992     { WM_ERASEBKGND, sent },
5993     { 0 }
5994 };
5995
5996 static const struct message WmPaint[] = {
5997     { WM_PAINT, sent },
5998     { 0 }
5999 };
6000
6001 static const struct message WmParentOnlyPaint[] = {
6002     { WM_PAINT, sent|parent },
6003     { 0 }
6004 };
6005
6006 static const struct message WmInvalidateParent[] = {
6007     { WM_NCPAINT, sent|parent },
6008     { WM_GETTEXT, sent|defwinproc|parent|optional },
6009     { WM_ERASEBKGND, sent|parent },
6010     { 0 }
6011 };
6012
6013 static const struct message WmInvalidateParentChild[] = {
6014     { WM_NCPAINT, sent|parent },
6015     { WM_GETTEXT, sent|defwinproc|parent|optional },
6016     { WM_ERASEBKGND, sent|parent },
6017     { WM_NCPAINT, sent },
6018     { WM_GETTEXT, sent|defwinproc|optional },
6019     { WM_ERASEBKGND, sent },
6020     { 0 }
6021 };
6022
6023 static const struct message WmInvalidateParentChild2[] = {
6024     { WM_ERASEBKGND, sent|parent },
6025     { WM_NCPAINT, sent },
6026     { WM_GETTEXT, sent|defwinproc|optional },
6027     { WM_ERASEBKGND, sent },
6028     { 0 }
6029 };
6030
6031 static const struct message WmParentPaint[] = {
6032     { WM_PAINT, sent|parent },
6033     { WM_PAINT, sent },
6034     { 0 }
6035 };
6036
6037 static const struct message WmParentPaintNc[] = {
6038     { WM_PAINT, sent|parent },
6039     { WM_PAINT, sent },
6040     { WM_NCPAINT, sent|beginpaint },
6041     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6042     { WM_ERASEBKGND, sent|beginpaint|optional },
6043     { 0 }
6044 };
6045
6046 static const struct message WmChildPaintNc[] = {
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 WmParentErasePaint[] = {
6055     { WM_PAINT, sent|parent },
6056     { WM_NCPAINT, sent|parent|beginpaint },
6057     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6058     { WM_ERASEBKGND, sent|parent|beginpaint|optional },
6059     { WM_PAINT, sent },
6060     { WM_NCPAINT, sent|beginpaint },
6061     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
6062     { WM_ERASEBKGND, sent|beginpaint|optional },
6063     { 0 }
6064 };
6065
6066 static const struct message WmParentOnlyNcPaint[] = {
6067     { WM_PAINT, sent|parent },
6068     { WM_NCPAINT, sent|parent|beginpaint },
6069     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
6070     { 0 }
6071 };
6072
6073 static const struct message WmSetParentStyle[] = {
6074     { WM_STYLECHANGING, sent|parent },
6075     { WM_STYLECHANGED, sent|parent },
6076     { 0 }
6077 };
6078
6079 static void test_paint_messages(void)
6080 {
6081     BOOL ret;
6082     RECT rect;
6083     POINT pt;
6084     MSG msg;
6085     HWND hparent, hchild;
6086     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6087     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
6088     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
6089                                 100, 100, 200, 200, 0, 0, 0, NULL);
6090     ok (hwnd != 0, "Failed to create overlapped window\n");
6091
6092     ShowWindow( hwnd, SW_SHOW );
6093     UpdateWindow( hwnd );
6094     flush_events();
6095     flush_sequence();
6096
6097     check_update_rgn( hwnd, 0 );
6098     SetRectRgn( hrgn, 10, 10, 20, 20 );
6099     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6100     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6101     check_update_rgn( hwnd, hrgn );
6102     SetRectRgn( hrgn2, 20, 20, 30, 30 );
6103     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
6104     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6105     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
6106     check_update_rgn( hwnd, hrgn );
6107     /* validate everything */
6108     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6109     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6110     check_update_rgn( hwnd, 0 );
6111
6112     /* test empty region */
6113     SetRectRgn( hrgn, 10, 10, 10, 15 );
6114     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6115     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6116     check_update_rgn( hwnd, 0 );
6117     /* test empty rect */
6118     SetRect( &rect, 10, 10, 10, 15 );
6119     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
6120     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
6121     check_update_rgn( hwnd, 0 );
6122
6123     /* flush pending messages */
6124     flush_events();
6125     flush_sequence();
6126
6127     GetClientRect( hwnd, &rect );
6128     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
6129     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
6130      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6131      */
6132     trace("testing InvalidateRect(0, NULL, FALSE)\n");
6133     SetRectEmpty( &rect );
6134     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
6135     check_update_rgn( hwnd, hrgn );
6136     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6137     flush_events();
6138     ok_sequence( WmPaint, "Paint", FALSE );
6139     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6140     check_update_rgn( hwnd, 0 );
6141
6142     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
6143      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
6144      */
6145     trace("testing ValidateRect(0, NULL)\n");
6146     SetRectEmpty( &rect );
6147     if (ValidateRect(0, &rect))  /* not supported on Win9x */
6148     {
6149         check_update_rgn( hwnd, hrgn );
6150         ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6151         flush_events();
6152         ok_sequence( WmPaint, "Paint", FALSE );
6153         RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
6154         check_update_rgn( hwnd, 0 );
6155     }
6156
6157     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
6158     SetLastError(0xdeadbeef);
6159     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
6160     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
6161        "wrong error code %d\n", GetLastError());
6162     check_update_rgn( hwnd, 0 );
6163     flush_events();
6164     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6165
6166     trace("testing ValidateRgn(0, NULL)\n");
6167     SetLastError(0xdeadbeef);
6168     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
6169     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6170        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6171        "wrong error code %d\n", GetLastError());
6172     check_update_rgn( hwnd, 0 );
6173     flush_events();
6174     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6175
6176     trace("testing UpdateWindow(NULL)\n");
6177     SetLastError(0xdeadbeef);
6178     ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
6179     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
6180        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
6181        "wrong error code %d\n", GetLastError());
6182     check_update_rgn( hwnd, 0 );
6183     flush_events();
6184     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6185
6186     /* now with frame */
6187     SetRectRgn( hrgn, -5, -5, 20, 20 );
6188
6189     /* flush pending messages */
6190     flush_events();
6191     flush_sequence();
6192     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6193     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6194
6195     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
6196     check_update_rgn( hwnd, hrgn );
6197
6198     flush_sequence();
6199     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6200     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6201
6202     flush_sequence();
6203     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
6204     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
6205
6206     GetClientRect( hwnd, &rect );
6207     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
6208     check_update_rgn( hwnd, hrgn );
6209
6210     flush_sequence();
6211     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
6212     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
6213
6214     flush_sequence();
6215     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
6216     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
6217     check_update_rgn( hwnd, 0 );
6218
6219     flush_sequence();
6220     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
6221     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
6222     check_update_rgn( hwnd, 0 );
6223
6224     flush_sequence();
6225     SetRectRgn( hrgn, 0, 0, 100, 100 );
6226     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
6227     SetRectRgn( hrgn, 0, 0, 50, 100 );
6228     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
6229     SetRectRgn( hrgn, 50, 0, 100, 100 );
6230     check_update_rgn( hwnd, hrgn );
6231     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6232     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
6233     check_update_rgn( hwnd, 0 );
6234
6235     flush_sequence();
6236     SetRectRgn( hrgn, 0, 0, 100, 100 );
6237     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6238     SetRectRgn( hrgn, 0, 0, 100, 50 );
6239     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
6240     ok_sequence( WmErase, "Erase", FALSE );
6241     SetRectRgn( hrgn, 0, 50, 100, 100 );
6242     check_update_rgn( hwnd, hrgn );
6243
6244     flush_sequence();
6245     SetRectRgn( hrgn, 0, 0, 100, 100 );
6246     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
6247     SetRectRgn( hrgn, 0, 0, 50, 50 );
6248     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
6249     ok_sequence( WmPaint, "Paint", FALSE );
6250
6251     flush_sequence();
6252     SetRectRgn( hrgn, -4, -4, -2, -2 );
6253     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6254     SetRectRgn( hrgn, -200, -200, -198, -198 );
6255     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
6256     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
6257
6258     flush_sequence();
6259     SetRectRgn( hrgn, -4, -4, -2, -2 );
6260     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6261     SetRectRgn( hrgn, -4, -4, -3, -3 );
6262     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
6263     SetRectRgn( hrgn, 0, 0, 1, 1 );
6264     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
6265     ok_sequence( WmPaint, "Paint", FALSE );
6266
6267     flush_sequence();
6268     SetRectRgn( hrgn, -4, -4, -1, -1 );
6269     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6270     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
6271     /* make sure no WM_PAINT was generated */
6272     flush_events();
6273     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
6274
6275     flush_sequence();
6276     SetRectRgn( hrgn, -4, -4, -1, -1 );
6277     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
6278     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6279     {
6280         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
6281         {
6282             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
6283             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
6284             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
6285             ret = GetUpdateRect( hwnd, &rect, FALSE );
6286             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
6287             /* this will send WM_NCPAINT and validate the non client area */
6288             ret = GetUpdateRect( hwnd, &rect, TRUE );
6289             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
6290         }
6291         DispatchMessage( &msg );
6292     }
6293     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
6294
6295     DestroyWindow( hwnd );
6296
6297     /* now test with a child window */
6298
6299     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
6300                               100, 100, 200, 200, 0, 0, 0, NULL);
6301     ok (hparent != 0, "Failed to create parent window\n");
6302
6303     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
6304                            10, 10, 100, 100, hparent, 0, 0, NULL);
6305     ok (hchild != 0, "Failed to create child window\n");
6306
6307     ShowWindow( hparent, SW_SHOW );
6308     UpdateWindow( hparent );
6309     UpdateWindow( hchild );
6310     flush_events();
6311     flush_sequence();
6312     log_all_parent_messages++;
6313
6314     SetRect( &rect, 0, 0, 50, 50 );
6315     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6316     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6317     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
6318
6319     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6320     pt.x = pt.y = 0;
6321     MapWindowPoints( hchild, hparent, &pt, 1 );
6322     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
6323     check_update_rgn( hchild, hrgn );
6324     SetRectRgn( hrgn, 0, 0, 50, 50 );
6325     check_update_rgn( hparent, hrgn );
6326     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6327     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
6328     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6329     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6330
6331     flush_events();
6332     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
6333
6334     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6335     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6336     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
6337     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
6338     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
6339
6340     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6341     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
6342     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
6343
6344     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6345     flush_sequence();
6346     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6347     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6348     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
6349
6350     /* flush all paint messages */
6351     flush_events();
6352     flush_sequence();
6353
6354     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
6355     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
6356     SetRectRgn( hrgn, 0, 0, 50, 50 );
6357     check_update_rgn( hparent, hrgn );
6358     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6359     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6360     SetRectRgn( hrgn, 0, 0, 50, 50 );
6361     check_update_rgn( hparent, hrgn );
6362
6363     /* flush all paint messages */
6364     flush_events();
6365     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6366     flush_sequence();
6367
6368     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
6369     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6370     SetRectRgn( hrgn, 0, 0, 50, 50 );
6371     check_update_rgn( hparent, hrgn );
6372     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6373     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6374     SetRectRgn( hrgn2, 10, 10, 50, 50 );
6375     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
6376     check_update_rgn( hparent, hrgn );
6377     /* flush all paint messages */
6378     flush_events();
6379     flush_sequence();
6380
6381     /* same as above but parent gets completely validated */
6382     SetRect( &rect, 20, 20, 30, 30 );
6383     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6384     SetRectRgn( hrgn, 20, 20, 30, 30 );
6385     check_update_rgn( hparent, hrgn );
6386     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
6387     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6388     check_update_rgn( hparent, 0 );  /* no update region */
6389     flush_events();
6390     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
6391
6392     /* make sure RDW_VALIDATE on child doesn't have the same effect */
6393     flush_sequence();
6394     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6395     SetRectRgn( hrgn, 20, 20, 30, 30 );
6396     check_update_rgn( hparent, hrgn );
6397     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
6398     SetRectRgn( hrgn, 20, 20, 30, 30 );
6399     check_update_rgn( hparent, hrgn );
6400
6401     /* same as above but normal WM_PAINT doesn't validate parent */
6402     flush_sequence();
6403     SetRect( &rect, 20, 20, 30, 30 );
6404     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6405     SetRectRgn( hrgn, 20, 20, 30, 30 );
6406     check_update_rgn( hparent, hrgn );
6407     /* no WM_PAINT in child while parent still pending */
6408     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6409     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6410     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6411     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
6412
6413     flush_sequence();
6414     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6415     /* no WM_PAINT in child while parent still pending */
6416     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6417     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6418     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
6419     /* now that parent is valid child should get WM_PAINT */
6420     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6421     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
6422     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6423     ok_sequence( WmEmptySeq, "No other message", FALSE );
6424
6425     /* same thing with WS_CLIPCHILDREN in parent */
6426     flush_sequence();
6427     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
6428     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6429     /* changing style invalidates non client area, but we need to invalidate something else to see it */
6430     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
6431     ok_sequence( WmEmptySeq, "No message", FALSE );
6432     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
6433     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
6434
6435     flush_sequence();
6436     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
6437     SetRectRgn( hrgn, 20, 20, 30, 30 );
6438     check_update_rgn( hparent, hrgn );
6439     /* no WM_PAINT in child while parent still pending */
6440     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6441     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
6442     /* WM_PAINT in parent first */
6443     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6444     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
6445
6446     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
6447     flush_sequence();
6448     SetRect( &rect, 0, 0, 30, 30 );
6449     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
6450     SetRectRgn( hrgn, 0, 0, 30, 30 );
6451     check_update_rgn( hparent, hrgn );
6452     flush_events();
6453     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
6454
6455     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6456     flush_sequence();
6457     SetRect( &rect, -10, 0, 30, 30 );
6458     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6459     SetRect( &rect, 0, 0, 20, 20 );
6460     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6461     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6462     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
6463
6464     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
6465     flush_sequence();
6466     SetRect( &rect, -10, 0, 30, 30 );
6467     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
6468     SetRect( &rect, 0, 0, 100, 100 );
6469     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
6470     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
6471     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
6472     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
6473     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
6474
6475     /* test RDW_INTERNALPAINT behavior */
6476
6477     flush_sequence();
6478     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
6479     flush_events();
6480     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6481
6482     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
6483     flush_events();
6484     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6485
6486     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6487     flush_events();
6488     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
6489
6490     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
6491     UpdateWindow( hparent );
6492     flush_events();
6493     flush_sequence();
6494     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
6495     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6496     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6497                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6498     flush_events();
6499     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
6500
6501     UpdateWindow( hparent );
6502     flush_events();
6503     flush_sequence();
6504     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
6505     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6506     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6507                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6508     flush_events();
6509     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6510
6511     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
6512     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
6513     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
6514     flush_events();
6515     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
6516
6517     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
6518     UpdateWindow( hparent );
6519     flush_events();
6520     flush_sequence();
6521     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
6522     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6523     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
6524                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6525     flush_events();
6526     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
6527
6528     UpdateWindow( hparent );
6529     flush_events();
6530     flush_sequence();
6531     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
6532     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
6533     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
6534                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
6535     flush_events();
6536     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
6537
6538     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
6539     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
6540
6541     UpdateWindow( hparent );
6542     flush_events();
6543     flush_sequence();
6544     trace("testing SetWindowPos(-10000, -10000) on child\n");
6545     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6546     check_update_rgn( hchild, 0 );
6547     flush_events();
6548
6549 #if 0 /* this one doesn't pass under Wine yet */
6550     UpdateWindow( hparent );
6551     flush_events();
6552     flush_sequence();
6553     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6554     ShowWindow( hchild, SW_MINIMIZE );
6555     check_update_rgn( hchild, 0 );
6556     flush_events();
6557 #endif
6558
6559     UpdateWindow( hparent );
6560     flush_events();
6561     flush_sequence();
6562     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6563     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6564     check_update_rgn( hparent, 0 );
6565     flush_events();
6566
6567     log_all_parent_messages--;
6568     DestroyWindow( hparent );
6569     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6570
6571     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6572
6573     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6574                               100, 100, 200, 200, 0, 0, 0, NULL);
6575     ok (hparent != 0, "Failed to create parent window\n");
6576
6577     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6578                            10, 10, 100, 100, hparent, 0, 0, NULL);
6579     ok (hchild != 0, "Failed to create child window\n");
6580
6581     ShowWindow( hparent, SW_SHOW );
6582     UpdateWindow( hparent );
6583     UpdateWindow( hchild );
6584     flush_events();
6585     flush_sequence();
6586
6587     /* moving child outside of parent boundaries changes update region */
6588     SetRect( &rect, 0, 0, 40, 40 );
6589     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6590     SetRectRgn( hrgn, 0, 0, 40, 40 );
6591     check_update_rgn( hchild, hrgn );
6592     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6593     SetRectRgn( hrgn, 10, 0, 40, 40 );
6594     check_update_rgn( hchild, hrgn );
6595     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6596     SetRectRgn( hrgn, 10, 10, 40, 40 );
6597     check_update_rgn( hchild, hrgn );
6598
6599     /* moving parent off-screen does too */
6600     SetRect( &rect, 0, 0, 100, 100 );
6601     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6602     SetRectRgn( hrgn, 0, 0, 100, 100 );
6603     check_update_rgn( hparent, hrgn );
6604     SetRectRgn( hrgn, 10, 10, 40, 40 );
6605     check_update_rgn( hchild, hrgn );
6606     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6607     SetRectRgn( hrgn, 20, 20, 100, 100 );
6608     check_update_rgn( hparent, hrgn );
6609     SetRectRgn( hrgn, 30, 30, 40, 40 );
6610     check_update_rgn( hchild, hrgn );
6611
6612     /* invalidated region is cropped by the parent rects */
6613     SetRect( &rect, 0, 0, 50, 50 );
6614     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6615     SetRectRgn( hrgn, 30, 30, 50, 50 );
6616     check_update_rgn( hchild, hrgn );
6617
6618     DestroyWindow( hparent );
6619     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6620     flush_sequence();
6621
6622     DeleteObject( hrgn );
6623     DeleteObject( hrgn2 );
6624 }
6625
6626 struct wnd_event
6627 {
6628     HWND hwnd;
6629     HANDLE grand_child;
6630     HANDLE start_event;
6631     HANDLE stop_event;
6632 };
6633
6634 static DWORD WINAPI thread_proc(void *param)
6635 {
6636     MSG msg;
6637     struct wnd_event *wnd_event = param;
6638
6639     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6640                                       100, 100, 200, 200, 0, 0, 0, NULL);
6641     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6642
6643     SetEvent(wnd_event->start_event);
6644
6645     while (GetMessage(&msg, 0, 0, 0))
6646     {
6647         TranslateMessage(&msg);
6648         DispatchMessage(&msg);
6649     }
6650
6651     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6652
6653     return 0;
6654 }
6655
6656 static DWORD CALLBACK create_grand_child_thread( void *param )
6657 {
6658     struct wnd_event *wnd_event = param;
6659     HWND hchild;
6660     MSG msg;
6661
6662     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
6663                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6664     ok (hchild != 0, "Failed to create child window\n");
6665     flush_events();
6666     flush_sequence();
6667     SetEvent( wnd_event->start_event );
6668
6669     for (;;)
6670     {
6671         MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
6672         if (!IsWindow( hchild )) break;  /* will be destroyed when parent thread exits */
6673         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6674     }
6675     return 0;
6676 }
6677
6678 static DWORD CALLBACK create_child_thread( void *param )
6679 {
6680     struct wnd_event *wnd_event = param;
6681     struct wnd_event child_event;
6682     DWORD ret, tid;
6683     MSG msg;
6684
6685     child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
6686                              WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
6687     ok (child_event.hwnd != 0, "Failed to create child window\n");
6688     SetFocus( child_event.hwnd );
6689     flush_events();
6690     flush_sequence();
6691     child_event.start_event = wnd_event->start_event;
6692     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
6693     for (;;)
6694     {
6695         DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6696         if (ret != 1) break;
6697         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6698     }
6699     ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
6700     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6701     return 0;
6702 }
6703
6704 static void test_interthread_messages(void)
6705 {
6706     HANDLE hThread;
6707     DWORD tid;
6708     WNDPROC proc;
6709     MSG msg;
6710     char buf[256];
6711     int len, expected_len;
6712     struct wnd_event wnd_event;
6713     BOOL ret;
6714
6715     wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
6716     if (!wnd_event.start_event)
6717     {
6718         win_skip("skipping interthread message test under win9x\n");
6719         return;
6720     }
6721
6722     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6723     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6724
6725     ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6726
6727     CloseHandle(wnd_event.start_event);
6728
6729     SetLastError(0xdeadbeef);
6730     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6731     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6732        "wrong error code %d\n", GetLastError());
6733
6734     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6735     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6736
6737     expected_len = lstrlenA("window caption text");
6738     memset(buf, 0, sizeof(buf));
6739     SetLastError(0xdeadbeef);
6740     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6741     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6742     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6743
6744     msg.hwnd = wnd_event.hwnd;
6745     msg.message = WM_GETTEXT;
6746     msg.wParam = sizeof(buf);
6747     msg.lParam = (LPARAM)buf;
6748     memset(buf, 0, sizeof(buf));
6749     SetLastError(0xdeadbeef);
6750     len = DispatchMessageA(&msg);
6751     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6752        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6753
6754     /* the following test causes an exception in user.exe under win9x */
6755     msg.hwnd = wnd_event.hwnd;
6756     msg.message = WM_TIMER;
6757     msg.wParam = 0;
6758     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6759     SetLastError(0xdeadbeef);
6760     len = DispatchMessageA(&msg);
6761     ok(!len && GetLastError() == 0xdeadbeef,
6762        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6763
6764     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6765     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6766
6767     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6768     CloseHandle(hThread);
6769
6770     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6771
6772     wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6773                               100, 100, 200, 200, 0, 0, 0, NULL);
6774     ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
6775     flush_sequence();
6776     log_all_parent_messages++;
6777     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6778     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
6779     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
6780     for (;;)
6781     {
6782         ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
6783         if (ret != 1) break;
6784         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
6785     }
6786     ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
6787     /* now wait for the thread without processing messages; this shouldn't deadlock */
6788     SetEvent( wnd_event.stop_event );
6789     ret = WaitForSingleObject( hThread, 5000 );
6790     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6791     CloseHandle( hThread );
6792
6793     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
6794     ok( !ret, "WaitForSingleObject failed %x\n", ret );
6795     CloseHandle( wnd_event.grand_child );
6796
6797     CloseHandle( wnd_event.start_event );
6798     CloseHandle( wnd_event.stop_event );
6799     flush_events();
6800     ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
6801     log_all_parent_messages--;
6802     DestroyWindow( wnd_event.hwnd );
6803 }
6804
6805
6806 static const struct message WmVkN[] = {
6807     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6808     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6809     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6810     { WM_CHAR, wparam|lparam, 'n', 1 },
6811     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6812     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6813     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6814     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6815     { 0 }
6816 };
6817 static const struct message WmShiftVkN[] = {
6818     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6819     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6820     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6821     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6822     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6823     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6824     { WM_CHAR, wparam|lparam, 'N', 1 },
6825     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6826     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6827     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6828     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6829     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6830     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6831     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6832     { 0 }
6833 };
6834 static const struct message WmCtrlVkN[] = {
6835     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6836     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6837     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6838     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6839     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6840     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6841     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6842     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6843     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6844     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6845     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6846     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6847     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6848     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6849     { 0 }
6850 };
6851 static const struct message WmCtrlVkN_2[] = {
6852     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6853     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6854     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6855     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6856     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6857     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6858     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6859     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6860     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6861     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6862     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6863     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6864     { 0 }
6865 };
6866 static const struct message WmAltVkN[] = {
6867     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6868     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6869     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6870     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6871     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6872     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6873     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6874     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6875     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6876     { HCBT_SYSCOMMAND, hook },
6877     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6878     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6879     { 0x00AE, sent|defwinproc|optional }, /* XP */
6880     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6881     { WM_INITMENU, sent|defwinproc },
6882     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6883     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6884     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6885     { WM_CAPTURECHANGED, sent|defwinproc },
6886     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6887     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6888     { WM_EXITMENULOOP, sent|defwinproc },
6889     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6890     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6891     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6892     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6893     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6894     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6895     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6896     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6897     { 0 }
6898 };
6899 static const struct message WmAltVkN_2[] = {
6900     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6901     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6902     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6903     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6904     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6905     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6906     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6907     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6908     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6909     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6910     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6911     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6912     { 0 }
6913 };
6914 static const struct message WmCtrlAltVkN[] = {
6915     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6916     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6917     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6918     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6919     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6920     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6921     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6922     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6923     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6924     { WM_CHAR, optional },
6925     { WM_CHAR, sent|optional },
6926     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6927     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6928     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6929     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6930     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6931     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6932     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6933     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6934     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6935     { 0 }
6936 };
6937 static const struct message WmCtrlShiftVkN[] = {
6938     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6939     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6940     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6941     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6942     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6943     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6944     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6945     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6946     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6947     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6948     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6949     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6950     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6951     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6952     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6953     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6954     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6955     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6956     { 0 }
6957 };
6958 static const struct message WmCtrlAltShiftVkN[] = {
6959     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6960     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6961     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6962     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6963     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6964     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6965     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6966     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6967     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6968     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6969     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6970     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6971     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6972     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6973     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6974     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6975     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6976     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6977     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6978     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6979     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6980     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6981     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6982     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6983     { 0 }
6984 };
6985 static const struct message WmAltPressRelease[] = {
6986     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6987     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6988     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6989     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6990     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6991     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6992     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6993     { HCBT_SYSCOMMAND, hook },
6994     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6995     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6996     { WM_INITMENU, sent|defwinproc },
6997     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6998     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6999     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7000
7001     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
7002
7003     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7004     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7005     { WM_CAPTURECHANGED, sent|defwinproc },
7006     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7007     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7008     { WM_EXITMENULOOP, sent|defwinproc },
7009     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
7010     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
7011     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
7012     { 0 }
7013 };
7014 static const struct message WmShiftMouseButton[] = {
7015     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7016     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7017     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
7018     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
7019     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
7020     { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
7021     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
7022     { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
7023     { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
7024     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
7025     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
7026     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
7027     { 0 }
7028 };
7029 static const struct message WmF1Seq[] = {
7030     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
7031     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
7032     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
7033     { WM_KEYF1, wparam|lparam, 0, 0 },
7034     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
7035     { WM_HELP, sent|defwinproc },
7036     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
7037     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
7038     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
7039     { 0 }
7040 };
7041 static const struct message WmVkAppsSeq[] = {
7042     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
7043     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
7044     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
7045     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
7046     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
7047     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
7048     { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
7049     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
7050     { 0 }
7051 };
7052 static const struct message WmVkF10Seq[] = {
7053     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7054     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7055     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7056     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7057     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7058     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7059     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7060     { HCBT_SYSCOMMAND, hook },
7061     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7062     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
7063     { WM_INITMENU, sent|defwinproc },
7064     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7065     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7066     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7067
7068     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
7069
7070     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7071     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7072     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
7073     { WM_CAPTURECHANGED, sent|defwinproc },
7074     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
7075     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
7076     { WM_EXITMENULOOP, sent|defwinproc },
7077     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7078     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7079     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7080     { 0 }
7081 };
7082 static const struct message WmShiftF10Seq[] = {
7083     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
7084     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
7085     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
7086     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
7087     { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
7088     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
7089     { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
7090     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
7091     { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
7092     { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
7093     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
7094     { HCBT_SYSCOMMAND, hook },
7095     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7096     { WM_INITMENU, sent|defwinproc },
7097     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
7098     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
7099     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
7100     { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
7101     { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
7102     { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
7103     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
7104     { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
7105     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
7106     { 0 }
7107 };
7108
7109 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
7110 {
7111     MSG msg;
7112
7113     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
7114     {
7115         struct recvd_message log_msg;
7116
7117         /* ignore some unwanted messages */
7118         if (msg.message == WM_MOUSEMOVE ||
7119             msg.message == WM_TIMER ||
7120             ignore_message( msg.message ))
7121             continue;
7122
7123         log_msg.hwnd = msg.hwnd;
7124         log_msg.message = msg.message;
7125         log_msg.flags = wparam|lparam;
7126         log_msg.wParam = msg.wParam;
7127         log_msg.lParam = msg.lParam;
7128         log_msg.descr = "accel";
7129         add_message(&log_msg);
7130
7131         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
7132         {
7133             TranslateMessage(&msg);
7134             DispatchMessage(&msg);
7135         }
7136     }
7137 }
7138
7139 static void test_accelerators(void)
7140 {
7141     RECT rc;
7142     POINT pt;
7143     SHORT state;
7144     HACCEL hAccel;
7145     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7146                                 100, 100, 200, 200, 0, 0, 0, NULL);
7147     BOOL ret;
7148
7149     assert(hwnd != 0);
7150     UpdateWindow(hwnd);
7151     flush_events();
7152     flush_sequence();
7153
7154     SetFocus(hwnd);
7155     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
7156
7157     state = GetKeyState(VK_SHIFT);
7158     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
7159     state = GetKeyState(VK_CAPITAL);
7160     ok(state == 0, "wrong CapsLock state %04x\n", state);
7161
7162     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
7163     assert(hAccel != 0);
7164
7165     flush_events();
7166     pump_msg_loop(hwnd, 0);
7167     flush_sequence();
7168
7169     trace("testing VK_N press/release\n");
7170     flush_sequence();
7171     keybd_event('N', 0, 0, 0);
7172     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7173     pump_msg_loop(hwnd, hAccel);
7174     if (!sequence_cnt)  /* we didn't get any message */
7175     {
7176         skip( "queuing key events not supported\n" );
7177         goto done;
7178     }
7179     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7180
7181     trace("testing Shift+VK_N press/release\n");
7182     flush_sequence();
7183     keybd_event(VK_SHIFT, 0, 0, 0);
7184     keybd_event('N', 0, 0, 0);
7185     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7186     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7187     pump_msg_loop(hwnd, hAccel);
7188     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7189
7190     trace("testing Ctrl+VK_N press/release\n");
7191     flush_sequence();
7192     keybd_event(VK_CONTROL, 0, 0, 0);
7193     keybd_event('N', 0, 0, 0);
7194     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7195     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7196     pump_msg_loop(hwnd, hAccel);
7197     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
7198
7199     trace("testing Alt+VK_N press/release\n");
7200     flush_sequence();
7201     keybd_event(VK_MENU, 0, 0, 0);
7202     keybd_event('N', 0, 0, 0);
7203     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7204     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7205     pump_msg_loop(hwnd, hAccel);
7206     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
7207
7208     trace("testing Ctrl+Alt+VK_N press/release 1\n");
7209     flush_sequence();
7210     keybd_event(VK_CONTROL, 0, 0, 0);
7211     keybd_event(VK_MENU, 0, 0, 0);
7212     keybd_event('N', 0, 0, 0);
7213     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7214     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7215     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7216     pump_msg_loop(hwnd, hAccel);
7217     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
7218
7219     ret = DestroyAcceleratorTable(hAccel);
7220     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7221
7222     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
7223     assert(hAccel != 0);
7224
7225     trace("testing VK_N press/release\n");
7226     flush_sequence();
7227     keybd_event('N', 0, 0, 0);
7228     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7229     pump_msg_loop(hwnd, hAccel);
7230     ok_sequence(WmVkN, "VK_N press/release", FALSE);
7231
7232     trace("testing Shift+VK_N press/release\n");
7233     flush_sequence();
7234     keybd_event(VK_SHIFT, 0, 0, 0);
7235     keybd_event('N', 0, 0, 0);
7236     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7237     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7238     pump_msg_loop(hwnd, hAccel);
7239     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
7240
7241     trace("testing Ctrl+VK_N press/release 2\n");
7242     flush_sequence();
7243     keybd_event(VK_CONTROL, 0, 0, 0);
7244     keybd_event('N', 0, 0, 0);
7245     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7246     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7247     pump_msg_loop(hwnd, hAccel);
7248     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
7249
7250     trace("testing Alt+VK_N press/release 2\n");
7251     flush_sequence();
7252     keybd_event(VK_MENU, 0, 0, 0);
7253     keybd_event('N', 0, 0, 0);
7254     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7255     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7256     pump_msg_loop(hwnd, hAccel);
7257     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
7258
7259     trace("testing Ctrl+Alt+VK_N press/release 2\n");
7260     flush_sequence();
7261     keybd_event(VK_CONTROL, 0, 0, 0);
7262     keybd_event(VK_MENU, 0, 0, 0);
7263     keybd_event('N', 0, 0, 0);
7264     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7265     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7266     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7267     pump_msg_loop(hwnd, hAccel);
7268     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
7269
7270     trace("testing Ctrl+Shift+VK_N press/release\n");
7271     flush_sequence();
7272     keybd_event(VK_CONTROL, 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_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7278     pump_msg_loop(hwnd, hAccel);
7279     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
7280
7281     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
7282     flush_sequence();
7283     keybd_event(VK_CONTROL, 0, 0, 0);
7284     keybd_event(VK_MENU, 0, 0, 0);
7285     keybd_event(VK_SHIFT, 0, 0, 0);
7286     keybd_event('N', 0, 0, 0);
7287     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
7288     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7289     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7290     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
7291     pump_msg_loop(hwnd, hAccel);
7292     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
7293
7294     ret = DestroyAcceleratorTable(hAccel);
7295     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
7296     hAccel = 0;
7297
7298     trace("testing Alt press/release\n");
7299     flush_sequence();
7300     keybd_event(VK_MENU, 0, 0, 0);
7301     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7302     keybd_event(VK_MENU, 0, 0, 0);
7303     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
7304     pump_msg_loop(hwnd, 0);
7305     /* this test doesn't pass in Wine for managed windows */
7306     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
7307
7308     trace("testing VK_F1 press/release\n");
7309     keybd_event(VK_F1, 0, 0, 0);
7310     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
7311     pump_msg_loop(hwnd, 0);
7312     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
7313
7314     trace("testing VK_APPS press/release\n");
7315     keybd_event(VK_APPS, 0, 0, 0);
7316     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
7317     pump_msg_loop(hwnd, 0);
7318     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
7319
7320     trace("testing VK_F10 press/release\n");
7321     keybd_event(VK_F10, 0, 0, 0);
7322     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7323     keybd_event(VK_F10, 0, 0, 0);
7324     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7325     pump_msg_loop(hwnd, 0);
7326     ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE);
7327
7328     trace("testing SHIFT+F10 press/release\n");
7329     keybd_event(VK_SHIFT, 0, 0, 0);
7330     keybd_event(VK_F10, 0, 0, 0);
7331     keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
7332     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7333     keybd_event(VK_ESCAPE, 0, 0, 0);
7334     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
7335     pump_msg_loop(hwnd, 0);
7336     ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
7337
7338     trace("testing Shift+MouseButton press/release\n");
7339     /* first, move mouse pointer inside of the window client area */
7340     GetClientRect(hwnd, &rc);
7341     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
7342     rc.left += (rc.right - rc.left)/2;
7343     rc.top += (rc.bottom - rc.top)/2;
7344     SetCursorPos(rc.left, rc.top);
7345     SetActiveWindow(hwnd);
7346
7347     flush_events();
7348     flush_sequence();
7349     GetCursorPos(&pt);
7350     if (pt.x == rc.left && pt.y == rc.top)
7351     {
7352         int i;
7353         keybd_event(VK_SHIFT, 0, 0, 0);
7354         mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
7355         mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7356         keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
7357         pump_msg_loop(hwnd, 0);
7358         for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
7359         if (i < sequence_cnt)
7360             ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
7361         else
7362             skip( "Shift+MouseButton event didn't get to the window\n" );
7363     }
7364
7365 done:
7366     if (hAccel) DestroyAcceleratorTable(hAccel);
7367     DestroyWindow(hwnd);
7368 }
7369
7370 /************* window procedures ********************/
7371
7372 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
7373                              WPARAM wParam, LPARAM lParam)
7374 {
7375     static LONG defwndproc_counter = 0;
7376     static LONG beginpaint_counter = 0;
7377     LRESULT ret;
7378     struct recvd_message msg;
7379
7380     if (ignore_message( message )) return 0;
7381
7382     switch (message)
7383     {
7384         case WM_ENABLE:
7385         {
7386             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
7387             ok((BOOL)wParam == !(style & WS_DISABLED),
7388                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
7389             break;
7390         }
7391
7392         case WM_CAPTURECHANGED:
7393             if (test_DestroyWindow_flag)
7394             {
7395                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7396                 if (style & WS_CHILD)
7397                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7398                 else if (style & WS_POPUP)
7399                     lParam = WND_POPUP_ID;
7400                 else
7401                     lParam = WND_PARENT_ID;
7402             }
7403             break;
7404
7405         case WM_NCDESTROY:
7406         {
7407             HWND capture;
7408
7409             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
7410             capture = GetCapture();
7411             if (capture)
7412             {
7413                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
7414                 trace("current capture %p, releasing...\n", capture);
7415                 ReleaseCapture();
7416             }
7417         }
7418         /* fall through */
7419         case WM_DESTROY:
7420             if (pGetAncestor)
7421                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
7422             if (test_DestroyWindow_flag)
7423             {
7424                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
7425                 if (style & WS_CHILD)
7426                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
7427                 else if (style & WS_POPUP)
7428                     lParam = WND_POPUP_ID;
7429                 else
7430                     lParam = WND_PARENT_ID;
7431             }
7432             break;
7433
7434         /* test_accelerators() depends on this */
7435         case WM_NCHITTEST:
7436             return HTCLIENT;
7437
7438         /* ignore */
7439         case WM_MOUSEMOVE:
7440         case WM_MOUSEACTIVATE:
7441         case WM_NCMOUSEMOVE:
7442         case WM_SETCURSOR:
7443         case WM_IME_SELECT:
7444             return 0;
7445     }
7446
7447     msg.hwnd = hwnd;
7448     msg.message = message;
7449     msg.flags = sent|wparam|lparam;
7450     if (defwndproc_counter) msg.flags |= defwinproc;
7451     if (beginpaint_counter) msg.flags |= beginpaint;
7452     msg.wParam = wParam;
7453     msg.lParam = lParam;
7454     msg.descr = "MsgCheckProc";
7455     add_message(&msg);
7456
7457     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
7458     {
7459         HWND parent = GetParent(hwnd);
7460         RECT rc;
7461         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
7462
7463         GetClientRect(parent, &rc);
7464         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
7465         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
7466               minmax->ptReserved.x, minmax->ptReserved.y,
7467               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
7468               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
7469               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
7470               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
7471
7472         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
7473            minmax->ptMaxSize.x, rc.right);
7474         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
7475            minmax->ptMaxSize.y, rc.bottom);
7476     }
7477
7478     if (message == WM_PAINT)
7479     {
7480         PAINTSTRUCT ps;
7481         beginpaint_counter++;
7482         BeginPaint( hwnd, &ps );
7483         beginpaint_counter--;
7484         EndPaint( hwnd, &ps );
7485         return 0;
7486     }
7487
7488     defwndproc_counter++;
7489     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
7490                   : DefWindowProcA(hwnd, message, wParam, lParam);
7491     defwndproc_counter--;
7492
7493     return ret;
7494 }
7495
7496 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7497 {
7498     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
7499 }
7500
7501 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7502 {
7503     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
7504 }
7505
7506 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7507 {
7508     static LONG defwndproc_counter = 0;
7509     LRESULT ret;
7510     struct recvd_message msg;
7511
7512     if (ignore_message( message )) return 0;
7513
7514     switch (message)
7515     {
7516     case WM_QUERYENDSESSION:
7517     case WM_ENDSESSION:
7518         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
7519         break;
7520     }
7521
7522     msg.hwnd = hwnd;
7523     msg.message = message;
7524     msg.flags = sent|wparam|lparam;
7525     if (defwndproc_counter) msg.flags |= defwinproc;
7526     msg.wParam = wParam;
7527     msg.lParam = lParam;
7528     msg.descr = "popup";
7529     add_message(&msg);
7530
7531     if (message == WM_CREATE)
7532     {
7533         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
7534         SetWindowLongA(hwnd, GWL_STYLE, style);
7535     }
7536
7537     defwndproc_counter++;
7538     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7539     defwndproc_counter--;
7540
7541     return ret;
7542 }
7543
7544 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7545 {
7546     static LONG defwndproc_counter = 0;
7547     static LONG beginpaint_counter = 0;
7548     LRESULT ret;
7549     struct recvd_message msg;
7550
7551     if (ignore_message( message )) return 0;
7552
7553     if (log_all_parent_messages ||
7554         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
7555         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
7556         message == WM_ENABLE || message == WM_ENTERIDLE ||
7557         message == WM_DRAWITEM || message == WM_COMMAND ||
7558         message == WM_IME_SETCONTEXT)
7559     {
7560         switch (message)
7561         {
7562             /* ignore */
7563             case WM_NCHITTEST:
7564                 return HTCLIENT;
7565             case WM_SETCURSOR:
7566             case WM_MOUSEMOVE:
7567             case WM_NCMOUSEMOVE:
7568                 return 0;
7569
7570             case WM_ERASEBKGND:
7571             {
7572                 RECT rc;
7573                 INT ret = GetClipBox((HDC)wParam, &rc);
7574
7575                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
7576                        ret, rc.left, rc.top, rc.right, rc.bottom);
7577                 break;
7578             }
7579         }
7580
7581         msg.hwnd = hwnd;
7582         msg.message = message;
7583         msg.flags = sent|parent|wparam|lparam;
7584         if (defwndproc_counter) msg.flags |= defwinproc;
7585         if (beginpaint_counter) msg.flags |= beginpaint;
7586         msg.wParam = wParam;
7587         msg.lParam = lParam;
7588         msg.descr = "parent";
7589         add_message(&msg);
7590     }
7591
7592     if (message == WM_PAINT)
7593     {
7594         PAINTSTRUCT ps;
7595         beginpaint_counter++;
7596         BeginPaint( hwnd, &ps );
7597         beginpaint_counter--;
7598         EndPaint( hwnd, &ps );
7599         return 0;
7600     }
7601
7602     defwndproc_counter++;
7603     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7604     defwndproc_counter--;
7605
7606     return ret;
7607 }
7608
7609 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7610 {
7611     static LONG defwndproc_counter = 0;
7612     LRESULT ret;
7613     struct recvd_message msg;
7614
7615     if (ignore_message( message )) return 0;
7616
7617     if (test_def_id)
7618     {
7619         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
7620         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
7621         if (after_end_dialog)
7622             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
7623         else
7624             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
7625     }
7626
7627     msg.hwnd = hwnd;
7628     msg.message = message;
7629     msg.flags = sent|wparam|lparam;
7630     if (defwndproc_counter) msg.flags |= defwinproc;
7631     msg.wParam = wParam;
7632     msg.lParam = lParam;
7633     msg.descr = "dialog";
7634     add_message(&msg);
7635
7636     defwndproc_counter++;
7637     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7638     defwndproc_counter--;
7639
7640     return ret;
7641 }
7642
7643 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7644 {
7645     static LONG defwndproc_counter = 0;
7646     LRESULT ret;
7647     struct recvd_message msg;
7648
7649     /* log only specific messages we are interested in */
7650     switch (message)
7651     {
7652 #if 0 /* probably log these as well */
7653     case WM_ACTIVATE:
7654     case WM_SETFOCUS:
7655     case WM_KILLFOCUS:
7656 #endif
7657     case WM_SHOWWINDOW:
7658     case WM_SIZE:
7659     case WM_MOVE:
7660     case WM_GETMINMAXINFO:
7661     case WM_WINDOWPOSCHANGING:
7662     case WM_WINDOWPOSCHANGED:
7663         break;
7664
7665     default: /* ignore */
7666         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7667         return DefWindowProcA(hwnd, message, wParam, lParam);
7668     }
7669
7670     msg.hwnd = hwnd;
7671     msg.message = message;
7672     msg.flags = sent|wparam|lparam;
7673     if (defwndproc_counter) msg.flags |= defwinproc;
7674     msg.wParam = wParam;
7675     msg.lParam = lParam;
7676     msg.descr = "show";
7677     add_message(&msg);
7678
7679     defwndproc_counter++;
7680     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7681     defwndproc_counter--;
7682
7683     return ret;
7684 }
7685
7686 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7687 {
7688     switch (msg)
7689     {
7690         case WM_CREATE: return 0;
7691         case WM_PAINT:
7692         {
7693             MSG msg2;
7694             static int i = 0;
7695
7696             if (i < 256)
7697             {
7698                 i++;
7699                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7700                 {
7701                     TranslateMessage(&msg2);
7702                     DispatchMessage(&msg2);
7703                 }
7704                 i--;
7705             }
7706             else ok(broken(1), "infinite loop\n");
7707             if ( i == 0)
7708                 paint_loop_done = 1;
7709             return DefWindowProcA(hWnd,msg,wParam,lParam);
7710         }
7711     }
7712     return DefWindowProcA(hWnd,msg,wParam,lParam);
7713 }
7714
7715 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7716 {
7717     static LONG defwndproc_counter = 0;
7718     LRESULT ret;
7719     struct recvd_message msg;
7720     DWORD queue_status;
7721
7722     if (ignore_message( message )) return 0;
7723
7724     if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
7725         message == WM_HOTKEY || message >= WM_APP)
7726     {
7727         msg.hwnd = hwnd;
7728         msg.message = message;
7729         msg.flags = sent|wparam|lparam;
7730         if (defwndproc_counter) msg.flags |= defwinproc;
7731         msg.wParam = wParam;
7732         msg.lParam = lParam;
7733         msg.descr = "HotkeyMsgCheckProcA";
7734         add_message(&msg);
7735     }
7736
7737     defwndproc_counter++;
7738     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7739     defwndproc_counter--;
7740
7741     if (message == WM_APP)
7742     {
7743         queue_status = GetQueueStatus(QS_HOTKEY);
7744         ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
7745         queue_status = GetQueueStatus(QS_POSTMESSAGE);
7746         ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
7747         PostMessageA(hwnd, WM_APP+1, 0, 0);
7748     }
7749     else if (message == WM_APP+1)
7750     {
7751         queue_status = GetQueueStatus(QS_HOTKEY);
7752         ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
7753     }
7754
7755     return ret;
7756 }
7757
7758 static BOOL RegisterWindowClasses(void)
7759 {
7760     WNDCLASSA cls;
7761     WNDCLASSW clsW;
7762
7763     cls.style = 0;
7764     cls.lpfnWndProc = MsgCheckProcA;
7765     cls.cbClsExtra = 0;
7766     cls.cbWndExtra = 0;
7767     cls.hInstance = GetModuleHandleA(0);
7768     cls.hIcon = 0;
7769     cls.hCursor = LoadCursorA(0, IDC_ARROW);
7770     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7771     cls.lpszMenuName = NULL;
7772     cls.lpszClassName = "TestWindowClass";
7773     if(!RegisterClassA(&cls)) return FALSE;
7774
7775     cls.lpfnWndProc = HotkeyMsgCheckProcA;
7776     cls.lpszClassName = "HotkeyWindowClass";
7777     if(!RegisterClassA(&cls)) return FALSE;
7778
7779     cls.lpfnWndProc = ShowWindowProcA;
7780     cls.lpszClassName = "ShowWindowClass";
7781     if(!RegisterClassA(&cls)) return FALSE;
7782
7783     cls.lpfnWndProc = PopupMsgCheckProcA;
7784     cls.lpszClassName = "TestPopupClass";
7785     if(!RegisterClassA(&cls)) return FALSE;
7786
7787     cls.lpfnWndProc = ParentMsgCheckProcA;
7788     cls.lpszClassName = "TestParentClass";
7789     if(!RegisterClassA(&cls)) return FALSE;
7790
7791     cls.lpfnWndProc = DefWindowProcA;
7792     cls.lpszClassName = "SimpleWindowClass";
7793     if(!RegisterClassA(&cls)) return FALSE;
7794
7795     cls.lpfnWndProc = PaintLoopProcA;
7796     cls.lpszClassName = "PaintLoopWindowClass";
7797     if(!RegisterClassA(&cls)) return FALSE;
7798
7799     cls.style = CS_NOCLOSE;
7800     cls.lpszClassName = "NoCloseWindowClass";
7801     if(!RegisterClassA(&cls)) return FALSE;
7802
7803     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7804     cls.style = 0;
7805     cls.hInstance = GetModuleHandleA(0);
7806     cls.hbrBackground = 0;
7807     cls.lpfnWndProc = TestDlgProcA;
7808     cls.lpszClassName = "TestDialogClass";
7809     if(!RegisterClassA(&cls)) return FALSE;
7810
7811     clsW.style = 0;
7812     clsW.lpfnWndProc = MsgCheckProcW;
7813     clsW.cbClsExtra = 0;
7814     clsW.cbWndExtra = 0;
7815     clsW.hInstance = GetModuleHandleW(0);
7816     clsW.hIcon = 0;
7817     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7818     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7819     clsW.lpszMenuName = NULL;
7820     clsW.lpszClassName = testWindowClassW;
7821     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7822
7823     return TRUE;
7824 }
7825
7826 static BOOL is_our_logged_class(HWND hwnd)
7827 {
7828     char buf[256];
7829
7830     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7831     {
7832         if (!lstrcmpiA(buf, "TestWindowClass") ||
7833             !lstrcmpiA(buf, "ShowWindowClass") ||
7834             !lstrcmpiA(buf, "TestParentClass") ||
7835             !lstrcmpiA(buf, "TestPopupClass") ||
7836             !lstrcmpiA(buf, "SimpleWindowClass") ||
7837             !lstrcmpiA(buf, "TestDialogClass") ||
7838             !lstrcmpiA(buf, "MDI_frame_class") ||
7839             !lstrcmpiA(buf, "MDI_client_class") ||
7840             !lstrcmpiA(buf, "MDI_child_class") ||
7841             !lstrcmpiA(buf, "my_button_class") ||
7842             !lstrcmpiA(buf, "my_edit_class") ||
7843             !lstrcmpiA(buf, "static") ||
7844             !lstrcmpiA(buf, "ListBox") ||
7845             !lstrcmpiA(buf, "ComboBox") ||
7846             !lstrcmpiA(buf, "MyDialogClass") ||
7847             !lstrcmpiA(buf, "#32770") ||
7848             !lstrcmpiA(buf, "#32768"))
7849         return TRUE;
7850     }
7851     return FALSE;
7852 }
7853
7854 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7855
7856     HWND hwnd;
7857
7858     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7859
7860     if (nCode == HCBT_CLICKSKIPPED)
7861     {
7862         /* ignore this event, XP sends it a lot when switching focus between windows */
7863         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7864     }
7865
7866     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7867     {
7868         struct recvd_message msg;
7869
7870         msg.hwnd = 0;
7871         msg.message = nCode;
7872         msg.flags = hook|wparam|lparam;
7873         msg.wParam = wParam;
7874         msg.lParam = lParam;
7875         msg.descr = "CBT";
7876         add_message(&msg);
7877
7878         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7879     }
7880
7881     if (nCode == HCBT_DESTROYWND)
7882     {
7883         if (test_DestroyWindow_flag)
7884         {
7885             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7886             if (style & WS_CHILD)
7887                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7888             else if (style & WS_POPUP)
7889                 lParam = WND_POPUP_ID;
7890             else
7891                 lParam = WND_PARENT_ID;
7892         }
7893     }
7894
7895     /* Log also SetFocus(0) calls */
7896     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7897
7898     if (is_our_logged_class(hwnd))
7899     {
7900         struct recvd_message msg;
7901
7902         msg.hwnd = hwnd;
7903         msg.message = nCode;
7904         msg.flags = hook|wparam|lparam;
7905         msg.wParam = wParam;
7906         msg.lParam = lParam;
7907         msg.descr = "CBT";
7908         add_message(&msg);
7909     }
7910     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7911 }
7912
7913 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7914                                     DWORD event,
7915                                     HWND hwnd,
7916                                     LONG object_id,
7917                                     LONG child_id,
7918                                     DWORD thread_id,
7919                                     DWORD event_time)
7920 {
7921     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7922
7923     /* ignore mouse cursor events */
7924     if (object_id == OBJID_CURSOR) return;
7925
7926     if (!hwnd || is_our_logged_class(hwnd))
7927     {
7928         struct recvd_message msg;
7929
7930         msg.hwnd = hwnd;
7931         msg.message = event;
7932         msg.flags = winevent_hook|wparam|lparam;
7933         msg.wParam = object_id;
7934         msg.lParam = child_id;
7935         msg.descr = "WEH";
7936         add_message(&msg);
7937     }
7938 }
7939
7940 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7941 static const WCHAR wszAnsi[] = {'U',0};
7942
7943 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7944 {
7945     switch (uMsg)
7946     {
7947     case CB_FINDSTRINGEXACT:
7948         trace("String: %p\n", (LPCWSTR)lParam);
7949         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7950             return 1;
7951         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7952             return 0;
7953         return -1;
7954     }
7955     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7956 }
7957
7958 static const struct message WmGetTextLengthAfromW[] = {
7959     { WM_GETTEXTLENGTH, sent },
7960     { WM_GETTEXT, sent|optional },
7961     { 0 }
7962 };
7963
7964 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7965
7966 /* dummy window proc for WM_GETTEXTLENGTH test */
7967 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7968 {
7969     switch(msg)
7970     {
7971     case WM_GETTEXTLENGTH:
7972         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7973     case WM_GETTEXT:
7974         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7975         return lstrlenW( (LPWSTR)lp );
7976     default:
7977         return DefWindowProcW( hwnd, msg, wp, lp );
7978     }
7979 }
7980
7981 static void test_message_conversion(void)
7982 {
7983     static const WCHAR wszMsgConversionClass[] =
7984         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7985     WNDCLASSW cls;
7986     LRESULT lRes;
7987     HWND hwnd;
7988     WNDPROC wndproc, newproc;
7989     BOOL ret;
7990
7991     cls.style = 0;
7992     cls.lpfnWndProc = MsgConversionProcW;
7993     cls.cbClsExtra = 0;
7994     cls.cbWndExtra = 0;
7995     cls.hInstance = GetModuleHandleW(NULL);
7996     cls.hIcon = NULL;
7997     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7998     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7999     cls.lpszMenuName = NULL;
8000     cls.lpszClassName = wszMsgConversionClass;
8001     /* this call will fail on Win9x, but that doesn't matter as this test is
8002      * meaningless on those platforms */
8003     if(!RegisterClassW(&cls)) return;
8004
8005     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
8006                            100, 100, 200, 200, 0, 0, 0, NULL);
8007     ok(hwnd != NULL, "Window creation failed\n");
8008
8009     /* {W, A} -> A */
8010
8011     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
8012     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8013     ok(lRes == 0, "String should have been converted\n");
8014     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8015     ok(lRes == 1, "String shouldn't have been converted\n");
8016
8017     /* {W, A} -> W */
8018
8019     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
8020     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8021     ok(lRes == 1, "String shouldn't have been converted\n");
8022     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8023     ok(lRes == 1, "String shouldn't have been converted\n");
8024
8025     /* Synchronous messages */
8026
8027     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8028     ok(lRes == 0, "String should have been converted\n");
8029     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8030     ok(lRes == 1, "String shouldn't have been converted\n");
8031
8032     /* Asynchronous messages */
8033
8034     SetLastError(0);
8035     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8036     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8037         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8038     SetLastError(0);
8039     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8040     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8041         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8042     SetLastError(0);
8043     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8044     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8045         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8046     SetLastError(0);
8047     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8048     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8049         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8050     SetLastError(0);
8051     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8052     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8053         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8054     SetLastError(0);
8055     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
8056     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8057         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8058     SetLastError(0);
8059     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8060     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8061         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8062     SetLastError(0);
8063     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
8064     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
8065         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
8066
8067     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
8068
8069     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
8070                           WS_OVERLAPPEDWINDOW,
8071                           100, 100, 200, 200, 0, 0, 0, NULL);
8072     assert(hwnd);
8073     flush_sequence();
8074     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
8075     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8076     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8077         "got bad length %ld\n", lRes );
8078
8079     flush_sequence();
8080     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
8081                             hwnd, WM_GETTEXTLENGTH, 0, 0);
8082     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
8083     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
8084         "got bad length %ld\n", lRes );
8085
8086     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
8087     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
8088     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8089     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8090                                      NULL, 0, NULL, NULL ) ||
8091         broken(lRes == lstrlenW(dummy_window_text) + 37),
8092         "got bad length %ld\n", lRes );
8093
8094     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
8095     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
8096     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
8097                                      NULL, 0, NULL, NULL ) ||
8098         broken(lRes == lstrlenW(dummy_window_text) + 37),
8099         "got bad length %ld\n", lRes );
8100
8101     ret = DestroyWindow(hwnd);
8102     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8103 }
8104
8105 struct timer_info
8106 {
8107     HWND hWnd;
8108     HANDLE handles[2];
8109     DWORD id;
8110 };
8111
8112 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8113 {
8114 }
8115
8116 static VOID CALLBACK tfunc_crash(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
8117 {
8118     /* Crash on purpose */
8119     *(volatile int *)0 = 2;
8120 }
8121
8122 #define TIMER_ID  0x19
8123
8124 static DWORD WINAPI timer_thread_proc(LPVOID x)
8125 {
8126     struct timer_info *info = x;
8127     DWORD r;
8128
8129     r = KillTimer(info->hWnd, 0x19);
8130     ok(r,"KillTimer failed in thread\n");
8131     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
8132     ok(r,"SetTimer failed in thread\n");
8133     ok(r==TIMER_ID,"SetTimer id different\n");
8134     r = SetEvent(info->handles[0]);
8135     ok(r,"SetEvent failed in thread\n");
8136     return 0;
8137 }
8138
8139 static void test_timers(void)
8140 {
8141     struct timer_info info;
8142     DWORD id;
8143     MSG msg;
8144
8145     info.hWnd = CreateWindow ("TestWindowClass", NULL,
8146        WS_OVERLAPPEDWINDOW ,
8147        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8148        NULL, NULL, 0);
8149
8150     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
8151     ok(info.id, "SetTimer failed\n");
8152     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
8153     info.handles[0] = CreateEvent(NULL,0,0,NULL);
8154     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
8155
8156     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
8157
8158     WaitForSingleObject(info.handles[1], INFINITE);
8159
8160     CloseHandle(info.handles[0]);
8161     CloseHandle(info.handles[1]);
8162
8163     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
8164
8165     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8166
8167     /* Test timer callback with crash */
8168     SetLastError(0xdeadbeef);
8169     info.hWnd = CreateWindowW(testWindowClassW, NULL,
8170                               WS_OVERLAPPEDWINDOW ,
8171                               CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8172                               NULL, NULL, 0);
8173     if ((!info.hWnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || /* Win9x/Me */
8174         (!pGetMenuInfo)) /* Win95/NT4 */
8175     {
8176         win_skip("Test would crash on Win9x/WinMe/NT4\n");
8177         DestroyWindow(info.hWnd);
8178         return;
8179     }
8180     info.id = SetTimer(info.hWnd, TIMER_ID, 0, tfunc_crash);
8181     ok(info.id, "SetTimer failed\n");
8182     Sleep(150);
8183     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8184
8185     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
8186 }
8187
8188 static int count = 0;
8189 static VOID CALLBACK callback_count(
8190     HWND hwnd,
8191     UINT uMsg,
8192     UINT_PTR idEvent,
8193     DWORD dwTime
8194 )
8195 {
8196     count++;
8197 }
8198
8199 static void test_timers_no_wnd(void)
8200 {
8201     UINT_PTR id, id2;
8202     MSG msg;
8203
8204     count = 0;
8205     id = SetTimer(NULL, 0, 100, callback_count);
8206     ok(id != 0, "did not get id from SetTimer.\n");
8207     id2 = SetTimer(NULL, id, 200, callback_count);
8208     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
8209     Sleep(150);
8210     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8211     ok(count == 0, "did not get zero count as expected (%i).\n", count);
8212     Sleep(150);
8213     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8214     ok(count == 1, "did not get one count as expected (%i).\n", count);
8215     KillTimer(NULL, id);
8216     Sleep(250);
8217     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
8218     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
8219 }
8220
8221 /* Various win events with arbitrary parameters */
8222 static const struct message WmWinEventsSeq[] = {
8223     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8224     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8225     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8226     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8227     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8228     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8229     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8230     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8231     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8232     /* our win event hook ignores OBJID_CURSOR events */
8233     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
8234     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
8235     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
8236     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
8237     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
8238     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
8239     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8240     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
8241     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
8242     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
8243     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
8244     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
8245     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
8246     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
8247     { 0 }
8248 };
8249 static const struct message WmWinEventCaretSeq[] = {
8250     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8251     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8252     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
8253     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
8254     { 0 }
8255 };
8256 static const struct message WmWinEventCaretSeq_2[] = {
8257     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8258     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8259     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
8260     { 0 }
8261 };
8262 static const struct message WmWinEventAlertSeq[] = {
8263     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
8264     { 0 }
8265 };
8266 static const struct message WmWinEventAlertSeq_2[] = {
8267     /* create window in the thread proc */
8268     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
8269     /* our test event */
8270     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
8271     { 0 }
8272 };
8273 static const struct message WmGlobalHookSeq_1[] = {
8274     /* create window in the thread proc */
8275     { HCBT_CREATEWND, hook|lparam, 0, 2 },
8276     /* our test events */
8277     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
8278     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
8279     { 0 }
8280 };
8281 static const struct message WmGlobalHookSeq_2[] = {
8282     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
8283     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
8284     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
8285     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
8286     { 0 }
8287 };
8288
8289 static const struct message WmMouseLLHookSeq[] = {
8290     { WM_MOUSEMOVE, hook },
8291     { WM_LBUTTONUP, hook },
8292     { WM_MOUSEMOVE, hook },
8293     { 0 }
8294 };
8295
8296 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
8297                                          DWORD event,
8298                                          HWND hwnd,
8299                                          LONG object_id,
8300                                          LONG child_id,
8301                                          DWORD thread_id,
8302                                          DWORD event_time)
8303 {
8304     char buf[256];
8305
8306     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8307     {
8308         if (!lstrcmpiA(buf, "TestWindowClass") ||
8309             !lstrcmpiA(buf, "static"))
8310         {
8311             struct recvd_message msg;
8312
8313             msg.hwnd = hwnd;
8314             msg.message = event;
8315             msg.flags = winevent_hook|wparam|lparam;
8316             msg.wParam = object_id;
8317             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
8318             msg.descr = "WEH_2";
8319             add_message(&msg);
8320         }
8321     }
8322 }
8323
8324 static HHOOK hCBT_global_hook;
8325 static DWORD cbt_global_hook_thread_id;
8326
8327 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
8328
8329     HWND hwnd;
8330     char buf[256];
8331
8332     if (nCode == HCBT_SYSCOMMAND)
8333     {
8334         struct recvd_message msg;
8335
8336         msg.hwnd = 0;
8337         msg.message = nCode;
8338         msg.flags = hook|wparam|lparam;
8339         msg.wParam = wParam;
8340         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8341         msg.descr = "CBT_2";
8342         add_message(&msg);
8343
8344         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8345     }
8346     /* WH_MOUSE_LL hook */
8347     if (nCode == HC_ACTION)
8348     {
8349         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
8350
8351         /* we can't test for real mouse events */
8352         if (mhll->flags & LLMHF_INJECTED)
8353         {
8354             struct recvd_message msg;
8355
8356             memset (&msg, 0, sizeof (msg));
8357             msg.message = wParam;
8358             msg.flags = hook;
8359             msg.descr = "CBT_2";
8360             add_message(&msg);
8361         }
8362         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8363     }
8364
8365     /* Log also SetFocus(0) calls */
8366     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
8367
8368     if (GetClassNameA(hwnd, buf, sizeof(buf)))
8369     {
8370         if (!lstrcmpiA(buf, "TestWindowClass") ||
8371             !lstrcmpiA(buf, "static"))
8372         {
8373             struct recvd_message msg;
8374
8375             msg.hwnd = hwnd;
8376             msg.message = nCode;
8377             msg.flags = hook|wparam|lparam;
8378             msg.wParam = wParam;
8379             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
8380             msg.descr = "CBT_2";
8381             add_message(&msg);
8382         }
8383     }
8384     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
8385 }
8386
8387 static DWORD WINAPI win_event_global_thread_proc(void *param)
8388 {
8389     HWND hwnd;
8390     MSG msg;
8391     HANDLE hevent = *(HANDLE *)param;
8392
8393     assert(pNotifyWinEvent);
8394
8395     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8396     assert(hwnd);
8397     trace("created thread window %p\n", hwnd);
8398
8399     *(HWND *)param = hwnd;
8400
8401     flush_sequence();
8402     /* this event should be received only by our new hook proc,
8403      * an old one does not expect an event from another thread.
8404      */
8405     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
8406     SetEvent(hevent);
8407
8408     while (GetMessage(&msg, 0, 0, 0))
8409     {
8410         TranslateMessage(&msg);
8411         DispatchMessage(&msg);
8412     }
8413     return 0;
8414 }
8415
8416 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
8417 {
8418     HWND hwnd;
8419     MSG msg;
8420     HANDLE hevent = *(HANDLE *)param;
8421
8422     flush_sequence();
8423     /* these events should be received only by our new hook proc,
8424      * an old one does not expect an event from another thread.
8425      */
8426
8427     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8428     assert(hwnd);
8429     trace("created thread window %p\n", hwnd);
8430
8431     *(HWND *)param = hwnd;
8432
8433     /* Windows doesn't like when a thread plays games with the focus,
8434        that leads to all kinds of misbehaviours and failures to activate
8435        a window. So, better keep next lines commented out.
8436     SetFocus(0);
8437     SetFocus(hwnd);*/
8438
8439     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8440     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8441
8442     SetEvent(hevent);
8443
8444     while (GetMessage(&msg, 0, 0, 0))
8445     {
8446         TranslateMessage(&msg);
8447         DispatchMessage(&msg);
8448     }
8449     return 0;
8450 }
8451
8452 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
8453 {
8454     HWND hwnd;
8455     MSG msg;
8456     HANDLE hevent = *(HANDLE *)param;
8457
8458     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
8459     assert(hwnd);
8460     trace("created thread window %p\n", hwnd);
8461
8462     *(HWND *)param = hwnd;
8463
8464     flush_sequence();
8465
8466     /* Windows doesn't like when a thread plays games with the focus,
8467      * that leads to all kinds of misbehaviours and failures to activate
8468      * a window. So, better don't generate a mouse click message below.
8469      */
8470     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8471     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8472     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8473
8474     SetEvent(hevent);
8475     while (GetMessage(&msg, 0, 0, 0))
8476     {
8477         TranslateMessage(&msg);
8478         DispatchMessage(&msg);
8479     }
8480     return 0;
8481 }
8482
8483 static void test_winevents(void)
8484 {
8485     BOOL ret;
8486     MSG msg;
8487     HWND hwnd, hwnd2;
8488     UINT i;
8489     HANDLE hthread, hevent;
8490     DWORD tid;
8491     HWINEVENTHOOK hhook;
8492     const struct message *events = WmWinEventsSeq;
8493
8494     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
8495                            WS_OVERLAPPEDWINDOW,
8496                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
8497                            NULL, NULL, 0);
8498     assert(hwnd);
8499
8500     /****** start of global hook test *************/
8501     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8502     if (!hCBT_global_hook)
8503     {
8504         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8505         skip( "cannot set global hook\n" );
8506         return;
8507     }
8508
8509     hevent = CreateEventA(NULL, 0, 0, NULL);
8510     assert(hevent);
8511     hwnd2 = hevent;
8512
8513     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
8514     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8515
8516     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8517
8518     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
8519
8520     flush_sequence();
8521     /* this one should be received only by old hook proc */
8522     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
8523     /* this one should be received only by old hook proc */
8524     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
8525
8526     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
8527
8528     ret = UnhookWindowsHookEx(hCBT_global_hook);
8529     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8530
8531     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8532     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8533     CloseHandle(hthread);
8534     CloseHandle(hevent);
8535     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8536     /****** end of global hook test *************/
8537
8538     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
8539     {
8540         ok(DestroyWindow(hwnd), "failed to destroy window\n");
8541         return;
8542     }
8543
8544     flush_sequence();
8545
8546     if (0)
8547     {
8548     /* this test doesn't pass under Win9x */
8549     /* win2k ignores events with hwnd == 0 */
8550     SetLastError(0xdeadbeef);
8551     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
8552     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
8553        GetLastError() == 0xdeadbeef, /* Win9x */
8554        "unexpected error %d\n", GetLastError());
8555     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8556     }
8557
8558     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
8559         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
8560
8561     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
8562
8563     /****** start of event filtering test *************/
8564     hhook = pSetWinEventHook(
8565         EVENT_OBJECT_SHOW, /* 0x8002 */
8566         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
8567         GetModuleHandleA(0), win_event_global_hook_proc,
8568         GetCurrentProcessId(), 0,
8569         WINEVENT_INCONTEXT);
8570     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8571
8572     hevent = CreateEventA(NULL, 0, 0, NULL);
8573     assert(hevent);
8574     hwnd2 = hevent;
8575
8576     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8577     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8578
8579     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8580
8581     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
8582
8583     flush_sequence();
8584     /* this one should be received only by old hook proc */
8585     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8586     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8587     /* this one should be received only by old hook proc */
8588     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8589
8590     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
8591
8592     ret = pUnhookWinEvent(hhook);
8593     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8594
8595     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8596     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8597     CloseHandle(hthread);
8598     CloseHandle(hevent);
8599     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8600     /****** end of event filtering test *************/
8601
8602     /****** start of out of context event test *************/
8603     hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
8604         win_event_global_hook_proc, GetCurrentProcessId(), 0,
8605         WINEVENT_OUTOFCONTEXT);
8606     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
8607
8608     hevent = CreateEventA(NULL, 0, 0, NULL);
8609     assert(hevent);
8610     hwnd2 = hevent;
8611
8612     flush_sequence();
8613
8614     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
8615     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8616
8617     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8618
8619     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
8620     /* process pending winevent messages */
8621     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8622     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
8623
8624     flush_sequence();
8625     /* this one should be received only by old hook proc */
8626     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
8627     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8628     /* this one should be received only by old hook proc */
8629     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8630
8631     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8632     /* process pending winevent messages */
8633     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8634     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8635
8636     ret = pUnhookWinEvent(hhook);
8637     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8638
8639     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8640     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8641     CloseHandle(hthread);
8642     CloseHandle(hevent);
8643     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8644     /****** end of out of context event test *************/
8645
8646     /****** start of MOUSE_LL hook test *************/
8647     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8648     /* WH_MOUSE_LL is not supported on Win9x platforms */
8649     if (!hCBT_global_hook)
8650     {
8651         win_skip("Skipping WH_MOUSE_LL test on this platform\n");
8652         goto skip_mouse_ll_hook_test;
8653     }
8654
8655     hevent = CreateEventA(NULL, 0, 0, NULL);
8656     assert(hevent);
8657     hwnd2 = hevent;
8658
8659     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8660     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8661
8662     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8663         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8664
8665     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8666     flush_sequence();
8667
8668     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8669     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8670     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8671
8672     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8673
8674     ret = UnhookWindowsHookEx(hCBT_global_hook);
8675     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8676
8677     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8678     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8679     CloseHandle(hthread);
8680     CloseHandle(hevent);
8681     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8682     /****** end of MOUSE_LL hook test *************/
8683 skip_mouse_ll_hook_test:
8684
8685     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8686 }
8687
8688 static void test_set_hook(void)
8689 {
8690     BOOL ret;
8691     HHOOK hhook;
8692     HWINEVENTHOOK hwinevent_hook;
8693
8694     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8695     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8696     UnhookWindowsHookEx(hhook);
8697
8698     if (0)
8699     {
8700     /* this test doesn't pass under Win9x: BUG! */
8701     SetLastError(0xdeadbeef);
8702     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8703     ok(!hhook, "global hook requires hModule != 0\n");
8704     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8705     }
8706
8707     SetLastError(0xdeadbeef);
8708     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8709     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8710     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8711        GetLastError() == 0xdeadbeef, /* Win9x */
8712        "unexpected error %d\n", GetLastError());
8713
8714     SetLastError(0xdeadbeef);
8715     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8716     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8717        GetLastError() == 0xdeadbeef, /* Win9x */
8718        "unexpected error %d\n", GetLastError());
8719
8720     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8721
8722     /* even process local incontext hooks require hmodule */
8723     SetLastError(0xdeadbeef);
8724     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8725         GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8726     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8727     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8728        GetLastError() == 0xdeadbeef, /* Win9x */
8729        "unexpected error %d\n", GetLastError());
8730
8731     /* even thread local incontext hooks require hmodule */
8732     SetLastError(0xdeadbeef);
8733     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8734         GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8735     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8736     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8737        GetLastError() == 0xdeadbeef, /* Win9x */
8738        "unexpected error %d\n", GetLastError());
8739
8740     if (0)
8741     {
8742     /* these 3 tests don't pass under Win9x */
8743     SetLastError(0xdeadbeef);
8744     hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
8745         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8746     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8747     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8748
8749     SetLastError(0xdeadbeef);
8750     hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
8751         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8752     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8753     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8754
8755     SetLastError(0xdeadbeef);
8756     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8757         0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8758     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8759     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8760     }
8761
8762     SetLastError(0xdeadbeef);
8763     hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
8764         GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8765     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8766     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8767     ret = pUnhookWinEvent(hwinevent_hook);
8768     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8769
8770 todo_wine {
8771     /* This call succeeds under win2k SP4, but fails under Wine.
8772        Does win2k test/use passed process id? */
8773     SetLastError(0xdeadbeef);
8774     hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
8775         0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8776     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8777     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8778     ret = pUnhookWinEvent(hwinevent_hook);
8779     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8780 }
8781
8782     SetLastError(0xdeadbeef);
8783     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8784     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8785         GetLastError() == 0xdeadbeef, /* Win9x */
8786         "unexpected error %d\n", GetLastError());
8787 }
8788
8789 static const struct message ScrollWindowPaint1[] = {
8790     { WM_PAINT, sent },
8791     { WM_ERASEBKGND, sent|beginpaint },
8792     { WM_GETTEXTLENGTH, sent|optional },
8793     { WM_PAINT, sent|optional },
8794     { WM_NCPAINT, sent|beginpaint|optional },
8795     { WM_GETTEXT, sent|beginpaint|optional },
8796     { WM_GETTEXT, sent|beginpaint|optional },
8797     { WM_GETTEXT, sent|beginpaint|optional },
8798     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
8799     { WM_ERASEBKGND, sent|beginpaint|optional },
8800     { 0 }
8801 };
8802
8803 static const struct message ScrollWindowPaint2[] = {
8804     { WM_PAINT, sent },
8805     { 0 }
8806 };
8807
8808 static void test_scrollwindowex(void)
8809 {
8810     HWND hwnd, hchild;
8811     RECT rect={0,0,130,130};
8812
8813     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8814             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8815             100, 100, 200, 200, 0, 0, 0, NULL);
8816     ok (hwnd != 0, "Failed to create overlapped window\n");
8817     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8818             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8819             10, 10, 150, 150, hwnd, 0, 0, NULL);
8820     ok (hchild != 0, "Failed to create child\n");
8821     UpdateWindow(hwnd);
8822     flush_events();
8823     flush_sequence();
8824
8825     /* scroll without the child window */
8826     trace("start scroll\n");
8827     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8828             SW_ERASE|SW_INVALIDATE);
8829     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8830     trace("end scroll\n");
8831     flush_sequence();
8832     flush_events();
8833     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8834     flush_events();
8835     flush_sequence();
8836
8837     /* Now without the SW_ERASE flag */
8838     trace("start scroll\n");
8839     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8840     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8841     trace("end scroll\n");
8842     flush_sequence();
8843     flush_events();
8844     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8845     flush_events();
8846     flush_sequence();
8847
8848     /* now scroll the child window as well */
8849     trace("start scroll\n");
8850     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8851             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8852     /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8853     /* windows sometimes a WM_MOVE */
8854     ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
8855     trace("end scroll\n");
8856     flush_sequence();
8857     flush_events();
8858     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8859     flush_events();
8860     flush_sequence();
8861
8862     /* now scroll with ScrollWindow() */
8863     trace("start scroll with ScrollWindow\n");
8864     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8865     trace("end scroll\n");
8866     flush_sequence();
8867     flush_events();
8868     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8869
8870     ok(DestroyWindow(hchild), "failed to destroy window\n");
8871     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8872     flush_sequence();
8873 }
8874
8875 static const struct message destroy_window_with_children[] = {
8876     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8877     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8878     { 0x0090, sent|optional },
8879     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8880     { 0x0090, sent|optional },
8881     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8882     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8883     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8884     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8885     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8886     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8887     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8888     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8889     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8890     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8891     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8892     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8893     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8894     { 0 }
8895 };
8896
8897 static void test_DestroyWindow(void)
8898 {
8899     BOOL ret;
8900     HWND parent, child1, child2, child3, child4, test;
8901     UINT_PTR child_id = WND_CHILD_ID + 1;
8902
8903     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8904                              100, 100, 200, 200, 0, 0, 0, NULL);
8905     assert(parent != 0);
8906     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8907                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8908     assert(child1 != 0);
8909     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8910                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8911     assert(child2 != 0);
8912     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8913                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8914     assert(child3 != 0);
8915     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8916                              0, 0, 50, 50, parent, 0, 0, NULL);
8917     assert(child4 != 0);
8918
8919     /* test owner/parent of child2 */
8920     test = GetParent(child2);
8921     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8922     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8923     if(pGetAncestor) {
8924         test = pGetAncestor(child2, GA_PARENT);
8925         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8926     }
8927     test = GetWindow(child2, GW_OWNER);
8928     ok(!test, "wrong owner %p\n", test);
8929
8930     test = SetParent(child2, parent);
8931     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8932
8933     /* test owner/parent of the parent */
8934     test = GetParent(parent);
8935     ok(!test, "wrong parent %p\n", test);
8936     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8937     if(pGetAncestor) {
8938         test = pGetAncestor(parent, GA_PARENT);
8939         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8940     }
8941     test = GetWindow(parent, GW_OWNER);
8942     ok(!test, "wrong owner %p\n", test);
8943
8944     /* test owner/parent of child1 */
8945     test = GetParent(child1);
8946     ok(test == parent, "wrong parent %p\n", test);
8947     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8948     if(pGetAncestor) {
8949         test = pGetAncestor(child1, GA_PARENT);
8950         ok(test == parent, "wrong parent %p\n", test);
8951     }
8952     test = GetWindow(child1, GW_OWNER);
8953     ok(!test, "wrong owner %p\n", test);
8954
8955     /* test owner/parent of child2 */
8956     test = GetParent(child2);
8957     ok(test == parent, "wrong parent %p\n", test);
8958     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8959     if(pGetAncestor) {
8960         test = pGetAncestor(child2, GA_PARENT);
8961         ok(test == parent, "wrong parent %p\n", test);
8962     }
8963     test = GetWindow(child2, GW_OWNER);
8964     ok(!test, "wrong owner %p\n", test);
8965
8966     /* test owner/parent of child3 */
8967     test = GetParent(child3);
8968     ok(test == child1, "wrong parent %p\n", test);
8969     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8970     if(pGetAncestor) {
8971         test = pGetAncestor(child3, GA_PARENT);
8972         ok(test == child1, "wrong parent %p\n", test);
8973     }
8974     test = GetWindow(child3, GW_OWNER);
8975     ok(!test, "wrong owner %p\n", test);
8976
8977     /* test owner/parent of child4 */
8978     test = GetParent(child4);
8979     ok(test == parent, "wrong parent %p\n", test);
8980     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8981     if(pGetAncestor) {
8982         test = pGetAncestor(child4, GA_PARENT);
8983         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8984     }
8985     test = GetWindow(child4, GW_OWNER);
8986     ok(test == parent, "wrong owner %p\n", test);
8987
8988     flush_sequence();
8989
8990     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8991            parent, child1, child2, child3, child4);
8992
8993     SetCapture(child4);
8994     test = GetCapture();
8995     ok(test == child4, "wrong capture window %p\n", test);
8996
8997     test_DestroyWindow_flag = TRUE;
8998     ret = DestroyWindow(parent);
8999     ok( ret, "DestroyWindow() error %d\n", GetLastError());
9000     test_DestroyWindow_flag = FALSE;
9001     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
9002
9003     ok(!IsWindow(parent), "parent still exists\n");
9004     ok(!IsWindow(child1), "child1 still exists\n");
9005     ok(!IsWindow(child2), "child2 still exists\n");
9006     ok(!IsWindow(child3), "child3 still exists\n");
9007     ok(!IsWindow(child4), "child4 still exists\n");
9008
9009     test = GetCapture();
9010     ok(!test, "wrong capture window %p\n", test);
9011 }
9012
9013
9014 static const struct message WmDispatchPaint[] = {
9015     { WM_NCPAINT, sent },
9016     { WM_GETTEXT, sent|defwinproc|optional },
9017     { WM_GETTEXT, sent|defwinproc|optional },
9018     { WM_ERASEBKGND, sent },
9019     { 0 }
9020 };
9021
9022 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9023 {
9024     if (message == WM_PAINT) return 0;
9025     return MsgCheckProcA( hwnd, message, wParam, lParam );
9026 }
9027
9028 static void test_DispatchMessage(void)
9029 {
9030     RECT rect;
9031     MSG msg;
9032     int count;
9033     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9034                                100, 100, 200, 200, 0, 0, 0, NULL);
9035     ShowWindow( hwnd, SW_SHOW );
9036     UpdateWindow( hwnd );
9037     flush_events();
9038     flush_sequence();
9039     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
9040
9041     SetRect( &rect, -5, -5, 5, 5 );
9042     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9043     count = 0;
9044     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9045     {
9046         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9047         else
9048         {
9049             flush_sequence();
9050             DispatchMessage( &msg );
9051             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
9052             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9053             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
9054             if (++count > 10) break;
9055         }
9056     }
9057     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
9058
9059     trace("now without DispatchMessage\n");
9060     flush_sequence();
9061     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
9062     count = 0;
9063     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
9064     {
9065         if (msg.message != WM_PAINT) DispatchMessage( &msg );
9066         else
9067         {
9068             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
9069             flush_sequence();
9070             /* this will send WM_NCCPAINT just like DispatchMessage does */
9071             GetUpdateRgn( hwnd, hrgn, TRUE );
9072             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
9073             DeleteObject( hrgn );
9074             GetClientRect( hwnd, &rect );
9075             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
9076             ok( !count, "Got multiple WM_PAINTs\n" );
9077             if (++count > 10) break;
9078         }
9079     }
9080     DestroyWindow(hwnd);
9081 }
9082
9083
9084 static const struct message WmUser[] = {
9085     { WM_USER, sent },
9086     { 0 }
9087 };
9088
9089 struct sendmsg_info
9090 {
9091     HWND  hwnd;
9092     DWORD timeout;
9093     DWORD ret;
9094 };
9095
9096 static DWORD CALLBACK send_msg_thread( LPVOID arg )
9097 {
9098     struct sendmsg_info *info = arg;
9099     SetLastError( 0xdeadbeef );
9100     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
9101     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
9102                         broken(GetLastError() == 0),  /* win9x */
9103                         "unexpected error %d\n", GetLastError());
9104     return 0;
9105 }
9106
9107 static void wait_for_thread( HANDLE thread )
9108 {
9109     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
9110     {
9111         MSG msg;
9112         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
9113     }
9114 }
9115
9116 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9117 {
9118     if (message == WM_USER) Sleep(200);
9119     return MsgCheckProcA( hwnd, message, wParam, lParam );
9120 }
9121
9122 static void test_SendMessageTimeout(void)
9123 {
9124     HANDLE thread;
9125     struct sendmsg_info info;
9126     DWORD tid;
9127     BOOL is_win9x;
9128
9129     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9130                                100, 100, 200, 200, 0, 0, 0, NULL);
9131     flush_events();
9132     flush_sequence();
9133
9134     info.timeout = 1000;
9135     info.ret = 0xdeadbeef;
9136     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9137     wait_for_thread( thread );
9138     CloseHandle( thread );
9139     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9140     ok_sequence( WmUser, "WmUser", FALSE );
9141
9142     info.timeout = 1;
9143     info.ret = 0xdeadbeef;
9144     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9145     Sleep(100);  /* SendMessageTimeout should time out here */
9146     wait_for_thread( thread );
9147     CloseHandle( thread );
9148     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9149     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9150
9151     /* 0 means infinite timeout (but not on win9x) */
9152     info.timeout = 0;
9153     info.ret = 0xdeadbeef;
9154     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9155     Sleep(100);
9156     wait_for_thread( thread );
9157     CloseHandle( thread );
9158     is_win9x = !info.ret;
9159     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9160     else ok_sequence( WmUser, "WmUser", FALSE );
9161
9162     /* timeout is treated as signed despite the prototype (but not on win9x) */
9163     info.timeout = 0x7fffffff;
9164     info.ret = 0xdeadbeef;
9165     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9166     Sleep(100);
9167     wait_for_thread( thread );
9168     CloseHandle( thread );
9169     ok( info.ret == 1, "SendMessageTimeout failed\n" );
9170     ok_sequence( WmUser, "WmUser", FALSE );
9171
9172     info.timeout = 0x80000000;
9173     info.ret = 0xdeadbeef;
9174     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9175     Sleep(100);
9176     wait_for_thread( thread );
9177     CloseHandle( thread );
9178     if (is_win9x)
9179     {
9180         ok( info.ret == 1, "SendMessageTimeout failed\n" );
9181         ok_sequence( WmUser, "WmUser", FALSE );
9182     }
9183     else
9184     {
9185         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
9186         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
9187     }
9188
9189     /* now check for timeout during message processing */
9190     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
9191     info.timeout = 100;
9192     info.ret = 0xdeadbeef;
9193     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
9194     wait_for_thread( thread );
9195     CloseHandle( thread );
9196     /* we should time out but still get the message */
9197     ok( info.ret == 0, "SendMessageTimeout failed\n" );
9198     ok_sequence( WmUser, "WmUser", FALSE );
9199
9200     DestroyWindow( info.hwnd );
9201 }
9202
9203
9204 /****************** edit message test *************************/
9205 #define ID_EDIT 0x1234
9206 static const struct message sl_edit_setfocus[] =
9207 {
9208     { HCBT_SETFOCUS, hook },
9209     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9210     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9211     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9212     { WM_SETFOCUS, sent|wparam, 0 },
9213     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9214     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
9215     { WM_CTLCOLOREDIT, sent|parent },
9216     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9217     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9218     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9219     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9220     { 0 }
9221 };
9222 static const struct message ml_edit_setfocus[] =
9223 {
9224     { HCBT_SETFOCUS, hook },
9225     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
9226     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9227     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9228     { WM_SETFOCUS, sent|wparam, 0 },
9229     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9230     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9231     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9232     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9233     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9234     { 0 }
9235 };
9236 static const struct message sl_edit_killfocus[] =
9237 {
9238     { HCBT_SETFOCUS, hook },
9239     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9240     { WM_KILLFOCUS, sent|wparam, 0 },
9241     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9242     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9243     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
9244     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
9245     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
9246     { 0 }
9247 };
9248 static const struct message sl_edit_lbutton_dblclk[] =
9249 {
9250     { WM_LBUTTONDBLCLK, sent },
9251     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9252     { 0 }
9253 };
9254 static const struct message sl_edit_lbutton_down[] =
9255 {
9256     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9257     { HCBT_SETFOCUS, hook },
9258     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9259     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9260     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9261     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9262     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9263     { WM_CTLCOLOREDIT, sent|parent },
9264     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9265     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9266     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9267     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9268     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9269     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9270     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9271     { WM_CTLCOLOREDIT, sent|parent|optional },
9272     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9273     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9274     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9275     { 0 }
9276 };
9277 static const struct message ml_edit_lbutton_down[] =
9278 {
9279     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
9280     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
9281     { HCBT_SETFOCUS, hook },
9282     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
9283     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
9284     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9285     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
9286     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
9287     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
9288     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9289     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9290     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
9291     { 0 }
9292 };
9293 static const struct message sl_edit_lbutton_up[] =
9294 {
9295     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9296     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9297     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9298     { WM_CAPTURECHANGED, sent|defwinproc },
9299     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
9300     { 0 }
9301 };
9302 static const struct message ml_edit_lbutton_up[] =
9303 {
9304     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
9305     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
9306     { WM_CAPTURECHANGED, sent|defwinproc },
9307     { 0 }
9308 };
9309
9310 static WNDPROC old_edit_proc;
9311
9312 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9313 {
9314     static LONG defwndproc_counter = 0;
9315     LRESULT ret;
9316     struct recvd_message msg;
9317
9318     if (ignore_message( message )) return 0;
9319
9320     msg.hwnd = hwnd;
9321     msg.message = message;
9322     msg.flags = sent|wparam|lparam;
9323     if (defwndproc_counter) msg.flags |= defwinproc;
9324     msg.wParam = wParam;
9325     msg.lParam = lParam;
9326     msg.descr = "edit";
9327     add_message(&msg);
9328
9329     defwndproc_counter++;
9330     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
9331     defwndproc_counter--;
9332
9333     return ret;
9334 }
9335
9336 static void subclass_edit(void)
9337 {
9338     WNDCLASSA cls;
9339
9340     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
9341
9342     old_edit_proc = cls.lpfnWndProc;
9343
9344     cls.hInstance = GetModuleHandle(0);
9345     cls.lpfnWndProc = edit_hook_proc;
9346     cls.lpszClassName = "my_edit_class";
9347     UnregisterClass(cls.lpszClassName, cls.hInstance);
9348     if (!RegisterClassA(&cls)) assert(0);
9349 }
9350
9351 static void test_edit_messages(void)
9352 {
9353     HWND hwnd, parent;
9354     DWORD dlg_code;
9355
9356     subclass_edit();
9357     log_all_parent_messages++;
9358
9359     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9360                              100, 100, 200, 200, 0, 0, 0, NULL);
9361     ok (parent != 0, "Failed to create parent window\n");
9362
9363     /* test single line edit */
9364     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
9365                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9366     ok(hwnd != 0, "Failed to create edit window\n");
9367
9368     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9369     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
9370
9371     ShowWindow(hwnd, SW_SHOW);
9372     UpdateWindow(hwnd);
9373     SetFocus(0);
9374     flush_sequence();
9375
9376     SetFocus(hwnd);
9377     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
9378
9379     SetFocus(0);
9380     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
9381
9382     SetFocus(0);
9383     ReleaseCapture();
9384     flush_sequence();
9385
9386     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9387     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
9388
9389     SetFocus(0);
9390     ReleaseCapture();
9391     flush_sequence();
9392
9393     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9394     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
9395
9396     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9397     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
9398
9399     DestroyWindow(hwnd);
9400
9401     /* test multiline edit */
9402     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
9403                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
9404     ok(hwnd != 0, "Failed to create edit window\n");
9405
9406     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
9407     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
9408        "wrong dlg_code %08x\n", dlg_code);
9409
9410     ShowWindow(hwnd, SW_SHOW);
9411     UpdateWindow(hwnd);
9412     SetFocus(0);
9413     flush_sequence();
9414
9415     SetFocus(hwnd);
9416     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
9417
9418     SetFocus(0);
9419     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
9420
9421     SetFocus(0);
9422     ReleaseCapture();
9423     flush_sequence();
9424
9425     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
9426     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
9427
9428     SetFocus(0);
9429     ReleaseCapture();
9430     flush_sequence();
9431
9432     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
9433     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
9434
9435     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
9436     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
9437
9438     DestroyWindow(hwnd);
9439     DestroyWindow(parent);
9440
9441     log_all_parent_messages--;
9442 }
9443
9444 /**************************** End of Edit test ******************************/
9445
9446 static const struct message WmKeyDownSkippedSeq[] =
9447 {
9448     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
9449     { 0 }
9450 };
9451 static const struct message WmKeyDownWasDownSkippedSeq[] =
9452 {
9453     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
9454     { 0 }
9455 };
9456 static const struct message WmKeyUpSkippedSeq[] =
9457 {
9458     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9459     { 0 }
9460 };
9461 static const struct message WmUserKeyUpSkippedSeq[] =
9462 {
9463     { WM_USER, sent },
9464     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
9465     { 0 }
9466 };
9467
9468 #define EV_STOP 0
9469 #define EV_SENDMSG 1
9470 #define EV_ACK 2
9471
9472 struct peekmsg_info
9473 {
9474     HWND  hwnd;
9475     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
9476 };
9477
9478 static DWORD CALLBACK send_msg_thread_2(void *param)
9479 {
9480     DWORD ret;
9481     struct peekmsg_info *info = param;
9482
9483     trace("thread: looping\n");
9484     SetEvent(info->hevent[EV_ACK]);
9485
9486     while (1)
9487     {
9488         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
9489
9490         switch (ret)
9491         {
9492         case WAIT_OBJECT_0 + EV_STOP:
9493             trace("thread: exiting\n");
9494             return 0;
9495
9496         case WAIT_OBJECT_0 + EV_SENDMSG:
9497             trace("thread: sending message\n");
9498             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
9499                 "SendNotifyMessageA failed error %u\n", GetLastError());
9500             SetEvent(info->hevent[EV_ACK]);
9501             break;
9502
9503         default:
9504             trace("unexpected return: %04x\n", ret);
9505             assert(0);
9506             break;
9507         }
9508     }
9509     return 0;
9510 }
9511
9512 static void test_PeekMessage(void)
9513 {
9514     MSG msg;
9515     HANDLE hthread;
9516     DWORD tid, qstatus;
9517     UINT qs_all_input = QS_ALLINPUT;
9518     UINT qs_input = QS_INPUT;
9519     BOOL ret;
9520     struct peekmsg_info info;
9521
9522     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
9523                               100, 100, 200, 200, 0, 0, 0, NULL);
9524     assert(info.hwnd);
9525     ShowWindow(info.hwnd, SW_SHOW);
9526     UpdateWindow(info.hwnd);
9527     SetFocus(info.hwnd);
9528
9529     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
9530     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
9531     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
9532
9533     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
9534     WaitForSingleObject(info.hevent[EV_ACK], 10000);
9535
9536     flush_events();
9537     flush_sequence();
9538
9539     SetLastError(0xdeadbeef);
9540     qstatus = GetQueueStatus(qs_all_input);
9541     if (GetLastError() == ERROR_INVALID_FLAGS)
9542     {
9543         trace("QS_RAWINPUT not supported on this platform\n");
9544         qs_all_input &= ~QS_RAWINPUT;
9545         qs_input &= ~QS_RAWINPUT;
9546     }
9547     if (qstatus & QS_POSTMESSAGE)
9548     {
9549         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
9550         qstatus = GetQueueStatus(qs_all_input);
9551     }
9552     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9553
9554     trace("signalling to send message\n");
9555     SetEvent(info.hevent[EV_SENDMSG]);
9556     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9557
9558     /* pass invalid QS_xxxx flags */
9559     SetLastError(0xdeadbeef);
9560     qstatus = GetQueueStatus(0xffffffff);
9561     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
9562     if (!qstatus)
9563     {
9564         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
9565         qstatus = GetQueueStatus(qs_all_input);
9566     }
9567     qstatus &= ~MAKELONG( 0x4000, 0x4000 );  /* sometimes set on Win95 */
9568     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
9569        "wrong qstatus %08x\n", qstatus);
9570
9571     msg.message = 0;
9572     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9573     ok(!ret,
9574        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9575         msg.message);
9576     ok_sequence(WmUser, "WmUser", FALSE);
9577
9578     qstatus = GetQueueStatus(qs_all_input);
9579     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9580
9581     keybd_event('N', 0, 0, 0);
9582     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9583     qstatus = GetQueueStatus(qs_all_input);
9584     if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
9585     {
9586         skip( "queuing key events not supported\n" );
9587         goto done;
9588     }
9589     ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
9590        /* keybd_event seems to trigger a sent message on NT4 */
9591        qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
9592        "wrong qstatus %08x\n", qstatus);
9593
9594     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9595     qstatus = GetQueueStatus(qs_all_input);
9596     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
9597        qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9598        "wrong qstatus %08x\n", qstatus);
9599
9600     InvalidateRect(info.hwnd, NULL, FALSE);
9601     qstatus = GetQueueStatus(qs_all_input);
9602     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
9603        qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
9604        "wrong qstatus %08x\n", qstatus);
9605
9606     trace("signalling to send message\n");
9607     SetEvent(info.hevent[EV_SENDMSG]);
9608     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9609
9610     qstatus = GetQueueStatus(qs_all_input);
9611     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9612        "wrong qstatus %08x\n", qstatus);
9613
9614     msg.message = 0;
9615     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
9616     if (ret && msg.message == WM_CHAR)
9617     {
9618         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9619         goto done;
9620     }
9621     ok(!ret,
9622        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9623         msg.message);
9624     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
9625     {
9626         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
9627         goto done;
9628     }
9629     ok_sequence(WmUser, "WmUser", FALSE);
9630
9631     qstatus = GetQueueStatus(qs_all_input);
9632     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9633        "wrong qstatus %08x\n", qstatus);
9634
9635     trace("signalling to send message\n");
9636     SetEvent(info.hevent[EV_SENDMSG]);
9637     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9638
9639     qstatus = GetQueueStatus(qs_all_input);
9640     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9641        "wrong qstatus %08x\n", qstatus);
9642
9643     msg.message = 0;
9644     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
9645     ok(!ret,
9646        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9647         msg.message);
9648     ok_sequence(WmUser, "WmUser", FALSE);
9649
9650     qstatus = GetQueueStatus(qs_all_input);
9651     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
9652        "wrong qstatus %08x\n", qstatus);
9653
9654     msg.message = 0;
9655     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9656     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9657        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9658        ret, msg.message, msg.wParam);
9659     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9660
9661     qstatus = GetQueueStatus(qs_all_input);
9662     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9663        "wrong qstatus %08x\n", qstatus);
9664
9665     msg.message = 0;
9666     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9667     ok(!ret,
9668        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9669         msg.message);
9670     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9671
9672     qstatus = GetQueueStatus(qs_all_input);
9673     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9674        "wrong qstatus %08x\n", qstatus);
9675
9676     msg.message = 0;
9677     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9678     ok(ret && msg.message == WM_PAINT,
9679        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9680     DispatchMessageA(&msg);
9681     ok_sequence(WmPaint, "WmPaint", FALSE);
9682
9683     qstatus = GetQueueStatus(qs_all_input);
9684     ok(qstatus == MAKELONG(0, QS_KEY),
9685        "wrong qstatus %08x\n", qstatus);
9686
9687     msg.message = 0;
9688     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9689     ok(!ret,
9690        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9691         msg.message);
9692     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9693
9694     qstatus = GetQueueStatus(qs_all_input);
9695     ok(qstatus == MAKELONG(0, QS_KEY),
9696        "wrong qstatus %08x\n", qstatus);
9697
9698     trace("signalling to send message\n");
9699     SetEvent(info.hevent[EV_SENDMSG]);
9700     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9701
9702     qstatus = GetQueueStatus(qs_all_input);
9703     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9704        "wrong qstatus %08x\n", qstatus);
9705
9706     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9707
9708     qstatus = GetQueueStatus(qs_all_input);
9709     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9710        "wrong qstatus %08x\n", qstatus);
9711
9712     msg.message = 0;
9713     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9714     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9715        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9716        ret, msg.message, msg.wParam);
9717     ok_sequence(WmUser, "WmUser", FALSE);
9718
9719     qstatus = GetQueueStatus(qs_all_input);
9720     ok(qstatus == MAKELONG(0, QS_KEY),
9721        "wrong qstatus %08x\n", qstatus);
9722
9723     msg.message = 0;
9724     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9725     ok(!ret,
9726        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9727         msg.message);
9728     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9729
9730     qstatus = GetQueueStatus(qs_all_input);
9731     ok(qstatus == MAKELONG(0, QS_KEY),
9732        "wrong qstatus %08x\n", qstatus);
9733
9734     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9735
9736     qstatus = GetQueueStatus(qs_all_input);
9737     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9738        "wrong qstatus %08x\n", qstatus);
9739
9740     trace("signalling to send message\n");
9741     SetEvent(info.hevent[EV_SENDMSG]);
9742     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9743
9744     qstatus = GetQueueStatus(qs_all_input);
9745     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9746        "wrong qstatus %08x\n", qstatus);
9747
9748     msg.message = 0;
9749     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9750     ok(!ret,
9751        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9752         msg.message);
9753     ok_sequence(WmUser, "WmUser", FALSE);
9754
9755     qstatus = GetQueueStatus(qs_all_input);
9756     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9757        "wrong qstatus %08x\n", qstatus);
9758
9759     msg.message = 0;
9760     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9761         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9762     else /* workaround for a missing QS_RAWINPUT support */
9763         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9764     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9765        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9766        ret, msg.message, msg.wParam);
9767     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9768
9769     qstatus = GetQueueStatus(qs_all_input);
9770     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9771        "wrong qstatus %08x\n", qstatus);
9772
9773     msg.message = 0;
9774     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9775         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9776     else /* workaround for a missing QS_RAWINPUT support */
9777         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9778     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9779        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9780        ret, msg.message, msg.wParam);
9781     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9782
9783     qstatus = GetQueueStatus(qs_all_input);
9784     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9785        "wrong qstatus %08x\n", qstatus);
9786
9787     msg.message = 0;
9788     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9789     ok(!ret,
9790        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9791         msg.message);
9792     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9793
9794     qstatus = GetQueueStatus(qs_all_input);
9795     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9796        "wrong qstatus %08x\n", qstatus);
9797
9798     msg.message = 0;
9799     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9800     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9801        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9802        ret, msg.message, msg.wParam);
9803     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9804
9805     qstatus = GetQueueStatus(qs_all_input);
9806     ok(qstatus == 0,
9807        "wrong qstatus %08x\n", qstatus);
9808
9809     msg.message = 0;
9810     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9811     ok(!ret,
9812        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9813         msg.message);
9814     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9815
9816     qstatus = GetQueueStatus(qs_all_input);
9817     ok(qstatus == 0,
9818        "wrong qstatus %08x\n", qstatus);
9819
9820     /* test whether presence of the quit flag in the queue affects
9821      * the queue state
9822      */
9823     PostQuitMessage(0x1234abcd);
9824
9825     qstatus = GetQueueStatus(qs_all_input);
9826     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9827        "wrong qstatus %08x\n", qstatus);
9828
9829     PostMessageA(info.hwnd, WM_USER, 0, 0);
9830
9831     qstatus = GetQueueStatus(qs_all_input);
9832     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9833        "wrong qstatus %08x\n", qstatus);
9834
9835     msg.message = 0;
9836     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9837     ok(ret && msg.message == WM_USER,
9838        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9839     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9840
9841     qstatus = GetQueueStatus(qs_all_input);
9842     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9843        "wrong qstatus %08x\n", qstatus);
9844
9845     msg.message = 0;
9846     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9847     ok(ret && msg.message == WM_QUIT,
9848        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9849     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9850     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9851     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9852
9853     qstatus = GetQueueStatus(qs_all_input);
9854 todo_wine {
9855     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9856        "wrong qstatus %08x\n", qstatus);
9857 }
9858
9859     msg.message = 0;
9860     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9861     ok(!ret,
9862        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9863         msg.message);
9864     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9865
9866     qstatus = GetQueueStatus(qs_all_input);
9867     ok(qstatus == 0,
9868        "wrong qstatus %08x\n", qstatus);
9869
9870     /* some GetMessage tests */
9871
9872     keybd_event('N', 0, 0, 0);
9873     qstatus = GetQueueStatus(qs_all_input);
9874     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9875
9876     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9877     qstatus = GetQueueStatus(qs_all_input);
9878     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9879
9880     if (qstatus)
9881     {
9882         ret = GetMessageA( &msg, 0, 0, 0 );
9883         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9884            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9885            ret, msg.message, msg.wParam);
9886         qstatus = GetQueueStatus(qs_all_input);
9887         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9888     }
9889
9890     if (qstatus)
9891     {
9892         ret = GetMessageA( &msg, 0, 0, 0 );
9893         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9894            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9895            ret, msg.message, msg.wParam);
9896         ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9897         qstatus = GetQueueStatus(qs_all_input);
9898         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9899     }
9900
9901     keybd_event('N', 0, 0, 0);
9902     qstatus = GetQueueStatus(qs_all_input);
9903     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9904
9905     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9906     qstatus = GetQueueStatus(qs_all_input);
9907     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9908
9909     if (qstatus & (QS_KEY << 16))
9910     {
9911         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9912         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9913            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9914            ret, msg.message, msg.wParam);
9915         ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
9916         qstatus = GetQueueStatus(qs_all_input);
9917         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9918     }
9919
9920     if (qstatus)
9921     {
9922         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9923         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9924            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9925            ret, msg.message, msg.wParam);
9926         qstatus = GetQueueStatus(qs_all_input);
9927         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9928     }
9929
9930     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9931     qstatus = GetQueueStatus(qs_all_input);
9932     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9933
9934     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9935     qstatus = GetQueueStatus(qs_all_input);
9936     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9937
9938     trace("signalling to send message\n");
9939     SetEvent(info.hevent[EV_SENDMSG]);
9940     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9941     qstatus = GetQueueStatus(qs_all_input);
9942     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9943        "wrong qstatus %08x\n", qstatus);
9944
9945     if (qstatus & (QS_KEY << 16))
9946     {
9947         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9948         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9949            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9950            ret, msg.message, msg.wParam);
9951         ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
9952         qstatus = GetQueueStatus(qs_all_input);
9953         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9954     }
9955
9956     if (qstatus)
9957     {
9958         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9959         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9960            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9961            ret, msg.message, msg.wParam);
9962         qstatus = GetQueueStatus(qs_all_input);
9963         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9964     }
9965 done:
9966     trace("signalling to exit\n");
9967     SetEvent(info.hevent[EV_STOP]);
9968
9969     WaitForSingleObject(hthread, INFINITE);
9970
9971     CloseHandle(hthread);
9972     CloseHandle(info.hevent[0]);
9973     CloseHandle(info.hevent[1]);
9974     CloseHandle(info.hevent[2]);
9975
9976     DestroyWindow(info.hwnd);
9977 }
9978
9979 static void wait_move_event(HWND hwnd, int x, int y)
9980 {
9981     MSG msg;
9982     DWORD time;
9983     BOOL  ret;
9984     int go = 0;
9985
9986     time = GetTickCount();
9987     while (GetTickCount() - time < 200 && !go) {
9988         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9989         go  = ret && msg.pt.x > x && msg.pt.y > y;
9990         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
9991     }
9992 }
9993
9994 #define STEP 5
9995 static void test_PeekMessage2(void)
9996 {
9997     HWND hwnd;
9998     BOOL ret;
9999     MSG msg;
10000     UINT message;
10001     DWORD time1, time2, time3;
10002     int x1, y1, x2, y2, x3, y3;
10003     POINT pos;
10004
10005     time1 = time2 = time3 = 0;
10006     x1 = y1 = x2 = y2 = x3 = y3 = 0;
10007
10008     /* Initialise window and make sure it is ready for events */
10009     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
10010                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
10011     assert(hwnd);
10012     trace("Window for test_PeekMessage2 %p\n", hwnd);
10013     ShowWindow(hwnd, SW_SHOW);
10014     UpdateWindow(hwnd);
10015     SetFocus(hwnd);
10016     GetCursorPos(&pos);
10017     SetCursorPos(100, 100);
10018     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
10019     flush_events();
10020
10021     /* Do initial mousemove, wait until we can see it
10022        and then do our test peek with PM_NOREMOVE. */
10023     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10024     wait_move_event(hwnd, 100-STEP, 100-STEP);
10025
10026     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10027     if (!ret)
10028     {
10029         skip( "queuing mouse events not supported\n" );
10030         goto done;
10031     }
10032     else
10033     {
10034         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10035         message = msg.message;
10036         time1 = msg.time;
10037         x1 = msg.pt.x;
10038         y1 = msg.pt.y;
10039         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10040     }
10041
10042     /* Allow time to advance a bit, and then simulate the user moving their
10043      * mouse around. After that we peek again with PM_NOREMOVE.
10044      * Although the previous mousemove message was never removed, the
10045      * mousemove we now peek should reflect the recent mouse movements
10046      * because the input queue will merge the move events. */
10047     Sleep(100);
10048     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10049     wait_move_event(hwnd, x1, y1);
10050
10051     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10052     ok(ret, "no message available\n");
10053     if (ret) {
10054         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10055         message = msg.message;
10056         time2 = msg.time;
10057         x2 = msg.pt.x;
10058         y2 = msg.pt.y;
10059         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10060         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
10061         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
10062     }
10063
10064     /* Have another go, to drive the point home */
10065     Sleep(100);
10066     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
10067     wait_move_event(hwnd, x2, y2);
10068
10069     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
10070     ok(ret, "no message available\n");
10071     if (ret) {
10072         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
10073         message = msg.message;
10074         time3 = msg.time;
10075         x3 = msg.pt.x;
10076         y3 = msg.pt.y;
10077         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
10078         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
10079         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
10080     }
10081
10082 done:
10083     DestroyWindow(hwnd);
10084     SetCursorPos(pos.x, pos.y);
10085     flush_events();
10086 }
10087
10088 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10089 {
10090     struct recvd_message msg;
10091
10092     if (ignore_message( message )) return 0;
10093
10094     msg.hwnd = hwnd;
10095     msg.message = message;
10096     msg.flags = sent|wparam|lparam;
10097     msg.wParam = wp;
10098     msg.lParam = lp;
10099     msg.descr = "dialog";
10100     add_message(&msg);
10101
10102     switch (message)
10103     {
10104     case WM_INITDIALOG:
10105         PostMessage(hwnd, WM_QUIT, 0x1234, 0x5678);
10106         PostMessage(hwnd, WM_USER, 0xdead, 0xbeef);
10107         return 0;
10108
10109     case WM_GETDLGCODE:
10110         return 0;
10111
10112     case WM_USER:
10113         EndDialog(hwnd, 0);
10114         break;
10115     }
10116
10117     return 1;
10118 }
10119
10120 static const struct message WmQuitDialogSeq[] = {
10121     { HCBT_CREATEWND, hook },
10122     { WM_SETFONT, sent },
10123     { WM_INITDIALOG, sent },
10124     { WM_CHANGEUISTATE, sent|optional },
10125     { HCBT_DESTROYWND, hook },
10126     { 0x0090, sent|optional }, /* Vista */
10127     { WM_DESTROY, sent },
10128     { WM_NCDESTROY, sent },
10129     { 0 }
10130 };
10131
10132 static void test_quit_message(void)
10133 {
10134     MSG msg;
10135     BOOL ret;
10136
10137     /* test using PostQuitMessage */
10138     flush_events();
10139     PostQuitMessage(0xbeef);
10140
10141     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10142     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10143     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10144     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10145
10146     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10147     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10148
10149     ret = GetMessage(&msg, NULL, 0, 0);
10150     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10151     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10152
10153     /* note: WM_QUIT message received after WM_USER message */
10154     ret = GetMessage(&msg, NULL, 0, 0);
10155     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10156     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10157     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
10158
10159     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10160     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
10161
10162     /* now test with PostThreadMessage - different behaviour! */
10163     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
10164
10165     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
10166     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
10167     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10168     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10169
10170     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
10171     ok(ret, "PostMessage failed with error %d\n", GetLastError());
10172
10173     /* note: we receive the WM_QUIT message first this time */
10174     ret = GetMessage(&msg, NULL, 0, 0);
10175     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
10176     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10177     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
10178
10179     ret = GetMessage(&msg, NULL, 0, 0);
10180     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
10181     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
10182
10183     flush_events();
10184     flush_sequence();
10185     ret = DialogBoxParam(GetModuleHandle(0), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
10186     ok(ret == 1, "expected 1, got %d\n", ret);
10187     ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
10188     memset(&msg, 0xab, sizeof(msg));
10189     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
10190     ok(ret, "PeekMessage failed\n");
10191     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
10192     ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
10193     ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
10194 }
10195
10196 static const struct message WmMouseHoverSeq[] = {
10197     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
10198     { WM_MOUSEACTIVATE, sent|optional },
10199     { WM_TIMER, sent|optional }, /* XP sends it */
10200     { WM_SYSTIMER, sent },
10201     { WM_MOUSEHOVER, sent|wparam, 0 },
10202     { 0 }
10203 };
10204
10205 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
10206 {
10207     MSG msg;
10208     DWORD start_ticks, end_ticks;
10209
10210     start_ticks = GetTickCount();
10211     /* add some deviation (50%) to cover not expected delays */
10212     start_ticks += timeout / 2;
10213
10214     do
10215     {
10216         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
10217         {
10218             /* Timer proc messages are not dispatched to the window proc,
10219              * and therefore not logged.
10220              */
10221             if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
10222             {
10223                 struct recvd_message s_msg;
10224
10225                 s_msg.hwnd = msg.hwnd;
10226                 s_msg.message = msg.message;
10227                 s_msg.flags = sent|wparam|lparam;
10228                 s_msg.wParam = msg.wParam;
10229                 s_msg.lParam = msg.lParam;
10230                 s_msg.descr = "msg_loop";
10231                 add_message(&s_msg);
10232             }
10233             DispatchMessage(&msg);
10234         }
10235
10236         end_ticks = GetTickCount();
10237
10238         /* inject WM_MOUSEMOVE to see how it changes tracking */
10239         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
10240         {
10241             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10242             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10243
10244             inject_mouse_move = FALSE;
10245         }
10246     } while (start_ticks + timeout >= end_ticks);
10247 }
10248
10249 static void test_TrackMouseEvent(void)
10250 {
10251     TRACKMOUSEEVENT tme;
10252     BOOL ret;
10253     HWND hwnd, hchild;
10254     RECT rc_parent, rc_child;
10255     UINT default_hover_time, hover_width = 0, hover_height = 0;
10256
10257 #define track_hover(track_hwnd, track_hover_time) \
10258     tme.cbSize = sizeof(tme); \
10259     tme.dwFlags = TME_HOVER; \
10260     tme.hwndTrack = track_hwnd; \
10261     tme.dwHoverTime = track_hover_time; \
10262     SetLastError(0xdeadbeef); \
10263     ret = pTrackMouseEvent(&tme); \
10264     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
10265
10266 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
10267     tme.cbSize = sizeof(tme); \
10268     tme.dwFlags = TME_QUERY; \
10269     tme.hwndTrack = (HWND)0xdeadbeef; \
10270     tme.dwHoverTime = 0xdeadbeef; \
10271     SetLastError(0xdeadbeef); \
10272     ret = pTrackMouseEvent(&tme); \
10273     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
10274     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
10275     ok(tme.dwFlags == (expected_track_flags), \
10276        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
10277     ok(tme.hwndTrack == (expected_track_hwnd), \
10278        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
10279     ok(tme.dwHoverTime == (expected_hover_time), \
10280        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
10281
10282 #define track_hover_cancel(track_hwnd) \
10283     tme.cbSize = sizeof(tme); \
10284     tme.dwFlags = TME_HOVER | TME_CANCEL; \
10285     tme.hwndTrack = track_hwnd; \
10286     tme.dwHoverTime = 0xdeadbeef; \
10287     SetLastError(0xdeadbeef); \
10288     ret = pTrackMouseEvent(&tme); \
10289     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
10290
10291     default_hover_time = 0xdeadbeef;
10292     SetLastError(0xdeadbeef);
10293     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
10294     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10295        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
10296     if (!ret) default_hover_time = 400;
10297     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
10298
10299     SetLastError(0xdeadbeef);
10300     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
10301     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10302        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
10303     if (!ret) hover_width = 4;
10304     SetLastError(0xdeadbeef);
10305     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
10306     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
10307        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
10308     if (!ret) hover_height = 4;
10309     trace("hover rect is %u x %d\n", hover_width, hover_height);
10310
10311     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
10312                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10313                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10314                           NULL, NULL, 0);
10315     assert(hwnd);
10316
10317     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
10318                           WS_CHILD | WS_BORDER | WS_VISIBLE,
10319                           50, 50, 200, 200, hwnd,
10320                           NULL, NULL, 0);
10321     assert(hchild);
10322
10323     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
10324     flush_events();
10325     flush_sequence();
10326
10327     tme.cbSize = 0;
10328     tme.dwFlags = TME_QUERY;
10329     tme.hwndTrack = (HWND)0xdeadbeef;
10330     tme.dwHoverTime = 0xdeadbeef;
10331     SetLastError(0xdeadbeef);
10332     ret = pTrackMouseEvent(&tme);
10333     ok(!ret, "TrackMouseEvent should fail\n");
10334     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
10335        "not expected error %u\n", GetLastError());
10336
10337     tme.cbSize = sizeof(tme);
10338     tme.dwFlags = TME_HOVER;
10339     tme.hwndTrack = (HWND)0xdeadbeef;
10340     tme.dwHoverTime = 0xdeadbeef;
10341     SetLastError(0xdeadbeef);
10342     ret = pTrackMouseEvent(&tme);
10343     ok(!ret, "TrackMouseEvent should fail\n");
10344     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10345        "not expected error %u\n", GetLastError());
10346
10347     tme.cbSize = sizeof(tme);
10348     tme.dwFlags = TME_HOVER | TME_CANCEL;
10349     tme.hwndTrack = (HWND)0xdeadbeef;
10350     tme.dwHoverTime = 0xdeadbeef;
10351     SetLastError(0xdeadbeef);
10352     ret = pTrackMouseEvent(&tme);
10353     ok(!ret, "TrackMouseEvent should fail\n");
10354     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
10355        "not expected error %u\n", GetLastError());
10356
10357     GetWindowRect(hwnd, &rc_parent);
10358     GetWindowRect(hchild, &rc_child);
10359     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
10360
10361     /* Process messages so that the system updates its internal current
10362      * window and hittest, otherwise TrackMouseEvent calls don't have any
10363      * effect.
10364      */
10365     flush_events();
10366     flush_sequence();
10367
10368     track_query(0, NULL, 0);
10369     track_hover(hchild, 0);
10370     track_query(0, NULL, 0);
10371
10372     flush_events();
10373     flush_sequence();
10374
10375     track_hover(hwnd, 0);
10376     tme.cbSize = sizeof(tme);
10377     tme.dwFlags = TME_QUERY;
10378     tme.hwndTrack = (HWND)0xdeadbeef;
10379     tme.dwHoverTime = 0xdeadbeef;
10380     SetLastError(0xdeadbeef);
10381     ret = pTrackMouseEvent(&tme);
10382     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
10383     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
10384     if (!tme.dwFlags)
10385     {
10386         skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
10387         DestroyWindow( hwnd );
10388         return;
10389     }
10390     ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
10391     ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
10392     ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
10393        tme.dwHoverTime, default_hover_time);
10394
10395     pump_msg_loop_timeout(default_hover_time, FALSE);
10396     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10397
10398     track_query(0, NULL, 0);
10399
10400     track_hover(hwnd, HOVER_DEFAULT);
10401     track_query(TME_HOVER, hwnd, default_hover_time);
10402
10403     Sleep(default_hover_time / 2);
10404     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10405     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10406
10407     track_query(TME_HOVER, hwnd, default_hover_time);
10408
10409     pump_msg_loop_timeout(default_hover_time, FALSE);
10410     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10411
10412     track_query(0, NULL, 0);
10413
10414     track_hover(hwnd, HOVER_DEFAULT);
10415     track_query(TME_HOVER, hwnd, default_hover_time);
10416
10417     pump_msg_loop_timeout(default_hover_time, TRUE);
10418     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
10419
10420     track_query(0, NULL, 0);
10421
10422     track_hover(hwnd, HOVER_DEFAULT);
10423     track_query(TME_HOVER, hwnd, default_hover_time);
10424     track_hover_cancel(hwnd);
10425
10426     DestroyWindow(hwnd);
10427
10428 #undef track_hover
10429 #undef track_query
10430 #undef track_hover_cancel
10431 }
10432
10433
10434 static const struct message WmSetWindowRgn[] = {
10435     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10436     { WM_NCCALCSIZE, sent|wparam, 1 },
10437     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
10438     { WM_GETTEXT, sent|defwinproc|optional },
10439     { WM_ERASEBKGND, sent|optional },
10440     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10441     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10442     { 0 }
10443 };
10444
10445 static const struct message WmSetWindowRgn_no_redraw[] = {
10446     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10447     { WM_NCCALCSIZE, sent|wparam, 1 },
10448     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
10449     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10450     { 0 }
10451 };
10452
10453 static const struct message WmSetWindowRgn_clear[] = {
10454     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
10455     { WM_NCCALCSIZE, sent|wparam, 1 },
10456     { WM_NCPAINT, sent|optional },
10457     { WM_GETTEXT, sent|defwinproc|optional },
10458     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
10459     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10460     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
10461     { WM_NCPAINT, sent|optional },
10462     { WM_GETTEXT, sent|defwinproc|optional },
10463     { WM_ERASEBKGND, sent|optional },
10464     { WM_WINDOWPOSCHANGING, sent|optional },
10465     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10466     { WM_NCPAINT, sent|optional },
10467     { WM_GETTEXT, sent|defwinproc|optional },
10468     { WM_ERASEBKGND, sent|optional },
10469     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
10470     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
10471     { WM_NCPAINT, sent|optional },
10472     { WM_GETTEXT, sent|defwinproc|optional },
10473     { WM_ERASEBKGND, sent|optional },
10474     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10475     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
10476     { 0 }
10477 };
10478
10479 static void test_SetWindowRgn(void)
10480 {
10481     HRGN hrgn;
10482     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10483                                 100, 100, 200, 200, 0, 0, 0, NULL);
10484     ok( hwnd != 0, "Failed to create overlapped window\n" );
10485
10486     ShowWindow( hwnd, SW_SHOW );
10487     UpdateWindow( hwnd );
10488     flush_events();
10489     flush_sequence();
10490
10491     trace("testing SetWindowRgn\n");
10492     hrgn = CreateRectRgn( 0, 0, 150, 150 );
10493     SetWindowRgn( hwnd, hrgn, TRUE );
10494     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
10495
10496     hrgn = CreateRectRgn( 30, 30, 160, 160 );
10497     SetWindowRgn( hwnd, hrgn, FALSE );
10498     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
10499
10500     hrgn = CreateRectRgn( 0, 0, 180, 180 );
10501     SetWindowRgn( hwnd, hrgn, TRUE );
10502     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
10503
10504     SetWindowRgn( hwnd, 0, TRUE );
10505     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
10506
10507     DestroyWindow( hwnd );
10508 }
10509
10510 /*************************** ShowWindow() test ******************************/
10511 static const struct message WmShowNormal[] = {
10512     { WM_SHOWWINDOW, sent|wparam, 1 },
10513     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10514     { HCBT_ACTIVATE, hook },
10515     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10516     { HCBT_SETFOCUS, hook },
10517     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10518     { 0 }
10519 };
10520 static const struct message WmShow[] = {
10521     { WM_SHOWWINDOW, sent|wparam, 1 },
10522     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10523     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10524     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10525     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10526     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10527     { 0 }
10528 };
10529 static const struct message WmShowNoActivate_1[] = {
10530     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10531     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10532     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10533     { WM_MOVE, sent|defwinproc|optional },
10534     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10535     { 0 }
10536 };
10537 static const struct message WmShowNoActivate_2[] = {
10538     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
10539     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10540     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10541     { WM_MOVE, sent|defwinproc },
10542     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10543     { HCBT_SETFOCUS, hook|optional },
10544     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10545     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10546     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10547     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10548     { 0 }
10549 };
10550 static const struct message WmShowNA_1[] = {
10551     { WM_SHOWWINDOW, sent|wparam, 1 },
10552     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10553     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10554     { 0 }
10555 };
10556 static const struct message WmShowNA_2[] = {
10557     { WM_SHOWWINDOW, sent|wparam, 1 },
10558     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
10559     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10560     { 0 }
10561 };
10562 static const struct message WmRestore_1[] = {
10563     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10564     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10565     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10566     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10567     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10568     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10569     { WM_MOVE, sent|defwinproc },
10570     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
10571     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10572     { 0 }
10573 };
10574 static const struct message WmRestore_2[] = {
10575     { WM_SHOWWINDOW, sent|wparam, 1 },
10576     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10577     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10578     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10579     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10580     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10581     { 0 }
10582 };
10583 static const struct message WmRestore_3[] = {
10584     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
10585     { WM_GETMINMAXINFO, sent },
10586     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10587     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
10588     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
10589     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
10590     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10591     { WM_MOVE, sent|defwinproc },
10592     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10593     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10594     { 0 }
10595 };
10596 static const struct message WmRestore_4[] = {
10597     { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
10598     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10599     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10600     { WM_MOVE, sent|defwinproc|optional },
10601     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10602     { 0 }
10603 };
10604 static const struct message WmRestore_5[] = {
10605     { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
10606     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10607     { HCBT_ACTIVATE, hook|optional },
10608     { HCBT_SETFOCUS, hook|optional },
10609     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10610     { WM_MOVE, sent|defwinproc|optional },
10611     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
10612     { 0 }
10613 };
10614 static const struct message WmHide_1[] = {
10615     { WM_SHOWWINDOW, sent|wparam, 0 },
10616     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
10617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
10618     { HCBT_ACTIVATE, hook|optional },
10619     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
10620     { 0 }
10621 };
10622 static const struct message WmHide_2[] = {
10623     { WM_SHOWWINDOW, sent|wparam, 0 },
10624     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10625     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
10626     { HCBT_ACTIVATE, hook|optional },
10627     { 0 }
10628 };
10629 static const struct message WmHide_3[] = {
10630     { WM_SHOWWINDOW, sent|wparam, 0 },
10631     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
10632     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10633     { HCBT_SETFOCUS, hook|optional },
10634     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10635     { 0 }
10636 };
10637 static const struct message WmShowMinimized_1[] = {
10638     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10639     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10640     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10641     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10642     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10643     { WM_MOVE, sent|defwinproc },
10644     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10645     { 0 }
10646 };
10647 static const struct message WmMinimize_1[] = {
10648     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10649     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10650     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10651     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10652     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10653     { WM_MOVE, sent|defwinproc },
10654     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10655     { 0 }
10656 };
10657 static const struct message WmMinimize_2[] = {
10658     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10659     { HCBT_SETFOCUS, hook|optional },
10660     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10661     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10662     { WM_MOVE, sent|defwinproc },
10663     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10664     { 0 }
10665 };
10666 static const struct message WmMinimize_3[] = {
10667     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10668     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10669     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10670     { WM_MOVE, sent|defwinproc },
10671     { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
10672     { 0 }
10673 };
10674 static const struct message WmShowMinNoActivate[] = {
10675     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10676     { WM_WINDOWPOSCHANGING, sent },
10677     { WM_WINDOWPOSCHANGED, sent },
10678     { WM_MOVE, sent|defwinproc|optional },
10679     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10680     { 0 }
10681 };
10682 static const struct message WmMinMax_1[] = {
10683     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
10684     { 0 }
10685 };
10686 static const struct message WmMinMax_2[] = {
10687     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10688     { WM_GETMINMAXINFO, sent|optional },
10689     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
10690     { HCBT_ACTIVATE, hook|optional },
10691     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10692     { HCBT_SETFOCUS, hook|optional },
10693     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10694     { WM_MOVE, sent|defwinproc|optional },
10695     { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
10696     { HCBT_SETFOCUS, hook|optional },
10697     { 0 }
10698 };
10699 static const struct message WmMinMax_3[] = {
10700     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
10701     { HCBT_SETFOCUS, hook|optional },
10702     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10703     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10704     { WM_MOVE, sent|defwinproc|optional },
10705     { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
10706     { 0 }
10707 };
10708 static const struct message WmMinMax_4[] = {
10709     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
10710     { 0 }
10711 };
10712 static const struct message WmShowMaximized_1[] = {
10713     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10714     { WM_GETMINMAXINFO, sent },
10715     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10716     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10717     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10718     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10719     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10720     { WM_MOVE, sent|defwinproc },
10721     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10722     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
10723     { 0 }
10724 };
10725 static const struct message WmShowMaximized_2[] = {
10726     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10727     { WM_GETMINMAXINFO, sent },
10728     { WM_WINDOWPOSCHANGING, sent|optional },
10729     { HCBT_ACTIVATE, hook|optional },
10730     { WM_WINDOWPOSCHANGED, sent|optional },
10731     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
10732     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
10733     { WM_WINDOWPOSCHANGING, sent|optional },
10734     { HCBT_SETFOCUS, hook|optional },
10735     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
10736     { WM_MOVE, sent|defwinproc },
10737     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10738     { HCBT_SETFOCUS, hook|optional },
10739     { 0 }
10740 };
10741 static const struct message WmShowMaximized_3[] = {
10742     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
10743     { WM_GETMINMAXINFO, sent|optional },
10744     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10745     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
10746     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
10747     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
10748     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
10749     { WM_MOVE, sent|defwinproc|optional },
10750     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
10751     { 0 }
10752 };
10753
10754 static void test_ShowWindow(void)
10755 {
10756     /* ShowWindow commands in random order */
10757     static const struct
10758     {
10759         INT cmd; /* ShowWindow command */
10760         LPARAM ret; /* ShowWindow return value */
10761         DWORD style; /* window style after the command */
10762         const struct message *msg; /* message sequence the command produces */
10763         INT wp_cmd, wp_flags; /* window placement after the command */
10764         POINT wp_min, wp_max; /* window placement after the command */
10765         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10766     } sw[] =
10767     {
10768 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
10769            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10770 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
10771            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10772 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1,
10773            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10774 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10775            SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
10776 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
10777            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10778 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
10779            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10780 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
10781            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10782 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10783            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10784 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
10785            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10786 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10787            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10788 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
10789            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10790 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
10791            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10792 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
10793            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10794 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10795            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10796 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
10797            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10798 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10799            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10800 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
10801            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10802 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10803            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10804 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10805            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10806 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10807            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10808 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10809            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10810 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
10811            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
10812 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
10813            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10814 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10815            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10816 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10817            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10818 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
10819            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10820 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
10821            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10822 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10823            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10824 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
10825            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10826 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
10827            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10828 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10829            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10830 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
10831            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10832 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10833            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10834 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
10835            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10836 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
10837            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10838 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10839            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10840 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
10841            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10842 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
10843            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10844 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
10845            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10846 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
10847            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10848 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10849            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10850 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
10851            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10852 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
10853            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10854 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
10855            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10856 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
10857            SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10858 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
10859            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10860 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
10861            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10862 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
10863            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10864 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
10865            SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10866 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10867            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10868 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
10869            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10870 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
10871            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10872 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
10873            SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
10874 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
10875            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10876 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
10877            SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
10878 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
10879            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
10880 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
10881            SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
10882     };
10883     HWND hwnd;
10884     DWORD style;
10885     LPARAM ret;
10886     INT i;
10887     WINDOWPLACEMENT wp;
10888     RECT win_rc, work_rc = {0, 0, 0, 0};
10889
10890 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10891     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10892                           120, 120, 90, 90,
10893                           0, 0, 0, NULL);
10894     assert(hwnd);
10895
10896     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10897     ok(style == 0, "expected style 0, got %08x\n", style);
10898
10899     flush_events();
10900     flush_sequence();
10901
10902     if (pGetMonitorInfoA && pMonitorFromPoint)
10903     {
10904         HMONITOR hmon;
10905         MONITORINFO mi;
10906         POINT pt = {0, 0};
10907
10908         SetLastError(0xdeadbeef);
10909         hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
10910         ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
10911
10912         mi.cbSize = sizeof(mi);
10913         SetLastError(0xdeadbeef);
10914         ret = pGetMonitorInfoA(hmon, &mi);
10915         ok(ret, "GetMonitorInfo error %u\n", GetLastError());
10916         trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n",
10917             mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom,
10918             mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
10919         work_rc = mi.rcWork;
10920     }
10921
10922     GetWindowRect(hwnd, &win_rc);
10923     OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
10924
10925     wp.length = sizeof(wp);
10926     SetLastError(0xdeadbeaf);
10927     ret = GetWindowPlacement(hwnd, &wp);
10928     ok(ret, "GetWindowPlacement error %u\n", GetLastError());
10929     ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
10930     ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
10931     ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
10932        "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
10933     ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
10934        "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
10935     if (work_rc.left || work_rc.top) todo_wine /* FIXME: remove once Wine is fixed */
10936     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10937        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10938         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10939         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10940         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10941     else
10942     ok(EqualRect(&win_rc, &wp.rcNormalPosition),
10943        "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
10944         win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
10945         wp.rcNormalPosition.left, wp.rcNormalPosition.top,
10946         wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
10947
10948     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10949     {
10950         static const char * const sw_cmd_name[13] =
10951         {
10952             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10953             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10954             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10955             "SW_NORMALNA" /* 0xCC */
10956         };
10957         char comment[64];
10958         INT idx; /* index into the above array of names */
10959
10960         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10961
10962         style = GetWindowLong(hwnd, GWL_STYLE);
10963         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10964         ret = ShowWindow(hwnd, sw[i].cmd);
10965         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10966         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10967         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10968
10969         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10970         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10971
10972         wp.length = sizeof(wp);
10973         SetLastError(0xdeadbeaf);
10974         ret = GetWindowPlacement(hwnd, &wp);
10975         ok(ret, "GetWindowPlacement error %u\n", GetLastError());
10976         ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
10977         ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
10978
10979         /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
10980         if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
10981             (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
10982         {
10983             ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
10984                (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
10985                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
10986         }
10987         else
10988         {
10989             if (wp.ptMinPosition.x != sw[i].wp_min.x || wp.ptMinPosition.y != sw[i].wp_min.y)
10990             todo_wine
10991             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
10992                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
10993             else
10994             ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
10995                "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
10996         }
10997
10998         if (wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
10999         todo_wine
11000         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11001            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11002         else
11003         ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
11004            "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
11005
11006 if (0) /* FIXME: Wine behaves completely different here */
11007         ok(EqualRect(&win_rc, &wp.rcNormalPosition),
11008            "expected %d,%d-%d,%d got %d,%d-%d,%d\n",
11009             win_rc.left, win_rc.top, win_rc.right, win_rc.bottom,
11010             wp.rcNormalPosition.left, wp.rcNormalPosition.top,
11011             wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
11012
11013         flush_events();
11014         flush_sequence();
11015     }
11016
11017     DestroyWindow(hwnd);
11018 }
11019
11020 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11021 {
11022     struct recvd_message msg;
11023
11024     if (ignore_message( message )) return 0;
11025
11026     msg.hwnd = hwnd;
11027     msg.message = message;
11028     msg.flags = sent|wparam|lparam;
11029     msg.wParam = wParam;
11030     msg.lParam = lParam;
11031     msg.descr = "dialog";
11032     add_message(&msg);
11033
11034     /* calling DefDlgProc leads to a recursion under XP */
11035
11036     switch (message)
11037     {
11038     case WM_INITDIALOG:
11039     case WM_GETDLGCODE:
11040         return 0;
11041     }
11042     return 1;
11043 }
11044
11045 static const struct message WmDefDlgSetFocus_1[] = {
11046     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11047     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11048     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11049     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11050     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11051     { HCBT_SETFOCUS, hook },
11052     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11053     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11054     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11055     { WM_SETFOCUS, sent|wparam, 0 },
11056     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11057     { WM_CTLCOLOREDIT, sent },
11058     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11059     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11060     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11061     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11062     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
11063     { 0 }
11064 };
11065 static const struct message WmDefDlgSetFocus_2[] = {
11066     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
11067     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
11068     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
11069     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
11070     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
11071     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11072     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
11073     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11074     { 0 }
11075 };
11076 /* Creation of a dialog */
11077 static const struct message WmCreateDialogParamSeq_1[] = {
11078     { HCBT_CREATEWND, hook },
11079     { WM_NCCREATE, sent },
11080     { WM_NCCALCSIZE, sent|wparam, 0 },
11081     { WM_CREATE, sent },
11082     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11083     { WM_SIZE, sent|wparam, SIZE_RESTORED },
11084     { WM_MOVE, sent },
11085     { WM_SETFONT, sent },
11086     { WM_INITDIALOG, sent },
11087     { WM_CHANGEUISTATE, sent|optional },
11088     { 0 }
11089 };
11090 /* Creation of a dialog */
11091 static const struct message WmCreateDialogParamSeq_2[] = {
11092     { HCBT_CREATEWND, hook },
11093     { WM_NCCREATE, sent },
11094     { WM_NCCALCSIZE, sent|wparam, 0 },
11095     { WM_CREATE, sent },
11096     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
11097     { WM_SIZE, sent|wparam, SIZE_RESTORED },
11098     { WM_MOVE, sent },
11099     { WM_CHANGEUISTATE, sent|optional },
11100     { 0 }
11101 };
11102
11103 static void test_dialog_messages(void)
11104 {
11105     WNDCLASS cls;
11106     HWND hdlg, hedit1, hedit2, hfocus;
11107     LRESULT ret;
11108
11109 #define set_selection(hctl, start, end) \
11110     ret = SendMessage(hctl, EM_SETSEL, start, end); \
11111     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
11112
11113 #define check_selection(hctl, start, end) \
11114     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
11115     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
11116
11117     subclass_edit();
11118
11119     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
11120                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
11121                           0, 0, 100, 100, 0, 0, 0, NULL);
11122     ok(hdlg != 0, "Failed to create custom dialog window\n");
11123
11124     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
11125                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11126                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
11127     ok(hedit1 != 0, "Failed to create edit control\n");
11128     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
11129                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
11130                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
11131     ok(hedit2 != 0, "Failed to create edit control\n");
11132
11133     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
11134     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
11135
11136     hfocus = GetFocus();
11137     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
11138
11139     SetFocus(hedit2);
11140     hfocus = GetFocus();
11141     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
11142
11143     check_selection(hedit1, 0, 0);
11144     check_selection(hedit2, 0, 0);
11145
11146     set_selection(hedit2, 0, -1);
11147     check_selection(hedit2, 0, 3);
11148
11149     SetFocus(0);
11150     hfocus = GetFocus();
11151     ok(hfocus == 0, "wrong focus %p\n", hfocus);
11152
11153     flush_sequence();
11154     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11155     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11156     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
11157
11158     hfocus = GetFocus();
11159     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11160
11161     check_selection(hedit1, 0, 5);
11162     check_selection(hedit2, 0, 3);
11163
11164     flush_sequence();
11165     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
11166     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
11167     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
11168
11169     hfocus = GetFocus();
11170     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
11171
11172     check_selection(hedit1, 0, 5);
11173     check_selection(hedit2, 0, 3);
11174
11175     EndDialog(hdlg, 0);
11176     DestroyWindow(hedit1);
11177     DestroyWindow(hedit2);
11178     DestroyWindow(hdlg);
11179     flush_sequence();
11180
11181 #undef set_selection
11182 #undef check_selection
11183
11184     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
11185     cls.lpszClassName = "MyDialogClass";
11186     cls.hInstance = GetModuleHandle(0);
11187     /* need a cast since a dlgproc is used as a wndproc */
11188     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
11189     if (!RegisterClass(&cls)) assert(0);
11190
11191     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
11192     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11193     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
11194     EndDialog(hdlg, 0);
11195     DestroyWindow(hdlg);
11196     flush_sequence();
11197
11198     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
11199     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
11200     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
11201     EndDialog(hdlg, 0);
11202     DestroyWindow(hdlg);
11203     flush_sequence();
11204
11205     UnregisterClass(cls.lpszClassName, cls.hInstance);
11206 }
11207
11208 static void test_nullCallback(void)
11209 {
11210     HWND hwnd;
11211
11212     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
11213                            100, 100, 200, 200, 0, 0, 0, NULL);
11214     ok (hwnd != 0, "Failed to create overlapped window\n");
11215
11216     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
11217     flush_events();
11218     DestroyWindow(hwnd);
11219 }
11220
11221 /* SetActiveWindow( 0 ) hwnd visible */
11222 static const struct message SetActiveWindowSeq0[] =
11223 {
11224     { HCBT_ACTIVATE, hook|optional },
11225     { WM_NCACTIVATE, sent|wparam, 0 },
11226     { WM_GETTEXT, sent|defwinproc|optional },
11227     { WM_ACTIVATE, sent|wparam, 0 },
11228     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11229     { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
11230     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11231     { WM_KILLFOCUS, sent|optional },
11232     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11233     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11234     { WM_NCACTIVATE, sent|wparam|optional, 1 },
11235     { WM_GETTEXT, sent|defwinproc|optional },
11236     { WM_ACTIVATE, sent|wparam|optional, 1 },
11237     { HCBT_SETFOCUS, hook|optional },
11238     { WM_KILLFOCUS, sent|defwinproc|optional },
11239     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11240     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
11241     { WM_IME_SETCONTEXT, sent|optional },
11242     { WM_IME_SETCONTEXT, sent|optional },
11243     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11244     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11245     { WM_SETFOCUS, sent|defwinproc|optional },
11246     { WM_GETTEXT, sent|optional },
11247     { 0 }
11248 };
11249 /* SetActiveWindow( hwnd ) hwnd visible */
11250 static const struct message SetActiveWindowSeq1[] =
11251 {
11252     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11253     { 0 }
11254 };
11255 /* SetActiveWindow( popup ) hwnd visible, popup visible */
11256 static const struct message SetActiveWindowSeq2[] =
11257 {
11258     { HCBT_ACTIVATE, hook },
11259     { WM_NCACTIVATE, sent|wparam, 0 },
11260     { WM_GETTEXT, sent|defwinproc|optional },
11261     { WM_ACTIVATE, sent|wparam, 0 },
11262     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11263     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
11264     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11265     { WM_NCPAINT, sent|optional },
11266     { WM_GETTEXT, sent|defwinproc|optional },
11267     { WM_ERASEBKGND, sent|optional },
11268     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11269     { WM_NCACTIVATE, sent|wparam, 1 },
11270     { WM_GETTEXT, sent|defwinproc|optional },
11271     { WM_ACTIVATE, sent|wparam, 1 },
11272     { HCBT_SETFOCUS, hook },
11273     { WM_KILLFOCUS, sent|defwinproc },
11274     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11275     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11276     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11277     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11278     { WM_SETFOCUS, sent|defwinproc },
11279     { WM_GETTEXT, sent|optional },
11280     { 0 }
11281 };
11282
11283 /* SetActiveWindow( hwnd ) hwnd not visible */
11284 static const struct message SetActiveWindowSeq3[] =
11285 {
11286     { HCBT_ACTIVATE, hook },
11287     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11288     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11289     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11290     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11291     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11292     { WM_ACTIVATEAPP, sent|wparam, 1 },
11293     { WM_ACTIVATEAPP, sent|wparam, 1 },
11294     { WM_NCACTIVATE, sent|wparam, 1 },
11295     { WM_ACTIVATE, sent|wparam, 1 },
11296     { HCBT_SETFOCUS, hook },
11297     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11298     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11299     { WM_SETFOCUS, sent|defwinproc },
11300     { 0 }
11301 };
11302 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
11303 static const struct message SetActiveWindowSeq4[] =
11304 {
11305     { HCBT_ACTIVATE, hook },
11306     { WM_NCACTIVATE, sent|wparam, 0 },
11307     { WM_GETTEXT, sent|defwinproc|optional },
11308     { WM_ACTIVATE, sent|wparam, 0 },
11309     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
11310     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
11311     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
11312     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11313     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
11314     { WM_NCACTIVATE, sent|wparam, 1 },
11315     { WM_GETTEXT, sent|defwinproc|optional },
11316     { WM_ACTIVATE, sent|wparam, 1 },
11317     { HCBT_SETFOCUS, hook },
11318     { WM_KILLFOCUS, sent|defwinproc },
11319     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
11320     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11321     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11322     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11323     { WM_SETFOCUS, sent|defwinproc },
11324     { 0 }
11325 };
11326
11327
11328 static void test_SetActiveWindow(void)
11329 {
11330     HWND hwnd, popup, ret;
11331
11332     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11333                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11334                            100, 100, 200, 200, 0, 0, 0, NULL);
11335
11336     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
11337                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
11338                            100, 100, 200, 200, hwnd, 0, 0, NULL);
11339
11340     ok(hwnd != 0, "Failed to create overlapped window\n");
11341     ok(popup != 0, "Failed to create popup window\n");
11342     SetForegroundWindow( popup );
11343     flush_sequence();
11344
11345     trace("SetActiveWindow(0)\n");
11346     ret = SetActiveWindow(0);
11347     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
11348     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
11349     flush_sequence();
11350
11351     trace("SetActiveWindow(hwnd), hwnd visible\n");
11352     ret = SetActiveWindow(hwnd);
11353     if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
11354     flush_sequence();
11355
11356     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
11357     ret = SetActiveWindow(popup);
11358     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
11359     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
11360     flush_sequence();
11361
11362     ShowWindow(hwnd, SW_HIDE);
11363     ShowWindow(popup, SW_HIDE);
11364     flush_sequence();
11365
11366     trace("SetActiveWindow(hwnd), hwnd not visible\n");
11367     ret = SetActiveWindow(hwnd);
11368     ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
11369     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
11370     flush_sequence();
11371
11372     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
11373     ret = SetActiveWindow(popup);
11374     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
11375     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
11376     flush_sequence();
11377
11378     trace("done\n");
11379
11380     DestroyWindow(hwnd);
11381 }
11382
11383 static const struct message SetForegroundWindowSeq[] =
11384 {
11385     { WM_NCACTIVATE, sent|wparam, 0 },
11386     { WM_GETTEXT, sent|defwinproc|optional },
11387     { WM_ACTIVATE, sent|wparam, 0 },
11388     { WM_ACTIVATEAPP, sent|wparam, 0 },
11389     { WM_KILLFOCUS, sent },
11390     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11391     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
11392     { 0 }
11393 };
11394
11395 static void test_SetForegroundWindow(void)
11396 {
11397     HWND hwnd;
11398
11399     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
11400                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11401                            100, 100, 200, 200, 0, 0, 0, NULL);
11402     ok (hwnd != 0, "Failed to create overlapped window\n");
11403     SetForegroundWindow( hwnd );
11404     flush_sequence();
11405
11406     trace("SetForegroundWindow( 0 )\n");
11407     SetForegroundWindow( 0 );
11408     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
11409     trace("SetForegroundWindow( GetDesktopWindow() )\n");
11410     SetForegroundWindow( GetDesktopWindow() );
11411     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
11412                                         "foreground top level window", FALSE);
11413     trace("done\n");
11414
11415     DestroyWindow(hwnd);
11416 }
11417
11418 static void test_dbcs_wm_char(void)
11419 {
11420     BYTE dbch[2];
11421     WCHAR wch, bad_wch;
11422     HWND hwnd, hwnd2;
11423     MSG msg;
11424     DWORD time;
11425     POINT pt;
11426     DWORD_PTR res;
11427     CPINFOEXA cpinfo;
11428     UINT i, j, k;
11429     struct message wmCharSeq[2];
11430
11431     if (!pGetCPInfoExA)
11432     {
11433         win_skip("GetCPInfoExA is not available\n");
11434         return;
11435     }
11436
11437     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
11438     if (cpinfo.MaxCharSize != 2)
11439     {
11440         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
11441         return;
11442     }
11443
11444     dbch[0] = dbch[1] = 0;
11445     wch = 0;
11446     bad_wch = cpinfo.UnicodeDefaultChar;
11447     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
11448         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
11449             for (k = 128; k <= 255; k++)
11450             {
11451                 char str[2];
11452                 WCHAR wstr[2];
11453                 str[0] = j;
11454                 str[1] = k;
11455                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
11456                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
11457                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
11458                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
11459                 {
11460                     dbch[0] = j;
11461                     dbch[1] = k;
11462                     wch = wstr[0];
11463                     break;
11464                 }
11465             }
11466
11467     if (!wch)
11468     {
11469         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
11470         return;
11471     }
11472     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
11473            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
11474
11475     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
11476                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11477     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
11478                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
11479     ok (hwnd != 0, "Failed to create overlapped window\n");
11480     ok (hwnd2 != 0, "Failed to create overlapped window\n");
11481     flush_sequence();
11482
11483     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
11484     wmCharSeq[0].message = WM_CHAR;
11485     wmCharSeq[0].flags = sent|wparam;
11486     wmCharSeq[0].wParam = wch;
11487
11488     /* posted message */
11489     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11490     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11491     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11492     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11493     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11494     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11495     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11496
11497     /* posted thread message */
11498     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
11499     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11500     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11501     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11502     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11503     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11504     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11505
11506     /* sent message */
11507     flush_sequence();
11508     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11509     ok_sequence( WmEmptySeq, "no messages", FALSE );
11510     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11511     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11512     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11513
11514     /* sent message with timeout */
11515     flush_sequence();
11516     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11517     ok_sequence( WmEmptySeq, "no messages", FALSE );
11518     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11519     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11520     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11521
11522     /* sent message with timeout and callback */
11523     flush_sequence();
11524     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
11525     ok_sequence( WmEmptySeq, "no messages", FALSE );
11526     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11527     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11528     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11529
11530     /* sent message with callback */
11531     flush_sequence();
11532     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11533     ok_sequence( WmEmptySeq, "no messages", FALSE );
11534     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
11535     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11536     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11537
11538     /* direct window proc call */
11539     flush_sequence();
11540     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11541     ok_sequence( WmEmptySeq, "no messages", FALSE );
11542     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11543     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11544
11545     /* dispatch message */
11546     msg.hwnd = hwnd;
11547     msg.message = WM_CHAR;
11548     msg.wParam = dbch[0];
11549     msg.lParam = 0;
11550     DispatchMessageA( &msg );
11551     ok_sequence( WmEmptySeq, "no messages", FALSE );
11552     msg.wParam = dbch[1];
11553     DispatchMessageA( &msg );
11554     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11555
11556     /* window handle is irrelevant */
11557     flush_sequence();
11558     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11559     ok_sequence( WmEmptySeq, "no messages", FALSE );
11560     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11561     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11562     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11563
11564     /* interleaved post and send */
11565     flush_sequence();
11566     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11567     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
11568     ok_sequence( WmEmptySeq, "no messages", FALSE );
11569     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11570     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11571     ok_sequence( WmEmptySeq, "no messages", FALSE );
11572     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11573     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11574     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
11575     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11576     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11577     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11578     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11579
11580     /* interleaved sent message and winproc */
11581     flush_sequence();
11582     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11583     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11584     ok_sequence( WmEmptySeq, "no messages", FALSE );
11585     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11586     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11587     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11588     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11589
11590     /* interleaved winproc and dispatch */
11591     msg.hwnd = hwnd;
11592     msg.message = WM_CHAR;
11593     msg.wParam = dbch[0];
11594     msg.lParam = 0;
11595     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
11596     DispatchMessageA( &msg );
11597     ok_sequence( WmEmptySeq, "no messages", FALSE );
11598     msg.wParam = dbch[1];
11599     DispatchMessageA( &msg );
11600     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11601     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
11602     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11603
11604     /* interleaved sends */
11605     flush_sequence();
11606     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
11607     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
11608     ok_sequence( WmEmptySeq, "no messages", FALSE );
11609     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
11610     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11611     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
11612     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11613
11614     /* dbcs WM_CHAR */
11615     flush_sequence();
11616     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
11617     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
11618     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11619
11620     /* other char messages are not magic */
11621     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
11622     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11623     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
11624     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11625     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11626     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
11627     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11628     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
11629     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
11630     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11631
11632     /* test retrieving messages */
11633
11634     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11635     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11636     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11637     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11638     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11639     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11640     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11641     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11642     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11643     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11644
11645     /* message filters */
11646     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11647     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
11648     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11649     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11650     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11651     /* message id is filtered, hwnd is not */
11652     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
11653     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
11654     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11655     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11656     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11657     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11658
11659     /* mixing GetMessage and PostMessage */
11660     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
11661     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
11662     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11663     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11664     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11665     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11666     time = msg.time;
11667     pt = msg.pt;
11668     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
11669     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11670     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11671     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11672     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11673     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
11674     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
11675     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 );
11676     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11677
11678     /* without PM_REMOVE */
11679     PostMessageW( hwnd, WM_CHAR, wch, 0 );
11680     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11681     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11682     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11683     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11684     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11685     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11686     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11687     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11688     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
11689     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11690     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11691     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11692     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
11693     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
11694     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
11695     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
11696     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
11697
11698     DestroyWindow(hwnd);
11699     DestroyWindow(hwnd2);
11700 }
11701
11702 #define ID_LISTBOX 0x000f
11703
11704 static const struct message wm_lb_setcursel_0[] =
11705 {
11706     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
11707     { WM_CTLCOLORLISTBOX, sent|parent },
11708     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11709     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11710     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11711     { 0 }
11712 };
11713 static const struct message wm_lb_setcursel_1[] =
11714 {
11715     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
11716     { WM_CTLCOLORLISTBOX, sent|parent },
11717     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
11718     { WM_CTLCOLORLISTBOX, sent|parent },
11719     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
11720     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11721     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
11722     { 0 }
11723 };
11724 static const struct message wm_lb_setcursel_2[] =
11725 {
11726     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
11727     { WM_CTLCOLORLISTBOX, sent|parent },
11728     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
11729     { WM_CTLCOLORLISTBOX, sent|parent },
11730     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
11731     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11732     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11733     { 0 }
11734 };
11735 static const struct message wm_lb_click_0[] =
11736 {
11737     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
11738     { HCBT_SETFOCUS, hook },
11739     { WM_KILLFOCUS, sent|parent },
11740     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
11741     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11742     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11743     { WM_SETFOCUS, sent|defwinproc },
11744
11745     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
11746     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
11747     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
11748     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
11749     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11750
11751     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
11752     { WM_CTLCOLORLISTBOX, sent|parent },
11753     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
11754     { WM_CTLCOLORLISTBOX, sent|parent },
11755     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
11756     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
11757
11758     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11759     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
11760
11761     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11762     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11763     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
11764     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
11765     { 0 }
11766 };
11767 static const struct message wm_lb_deletestring[] =
11768 {
11769     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11770     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11771     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11772     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11773     { 0 }
11774 };
11775 static const struct message wm_lb_deletestring_reset[] =
11776 {
11777     { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
11778     { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
11779     { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
11780     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11781     { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
11782     { 0 }
11783 };
11784
11785 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
11786
11787 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
11788
11789 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11790 {
11791     static LONG defwndproc_counter = 0;
11792     LRESULT ret;
11793     struct recvd_message msg;
11794
11795     /* do not log painting messages */
11796     if (message != WM_PAINT &&
11797         message != WM_NCPAINT &&
11798         message != WM_SYNCPAINT &&
11799         message != WM_ERASEBKGND &&
11800         message != WM_NCHITTEST &&
11801         message != WM_GETTEXT &&
11802         !ignore_message( message ))
11803     {
11804         msg.hwnd = hwnd;
11805         msg.message = message;
11806         msg.flags = sent|wparam|lparam;
11807         if (defwndproc_counter) msg.flags |= defwinproc;
11808         msg.wParam = wp;
11809         msg.lParam = lp;
11810         msg.descr = "listbox";
11811         add_message(&msg);
11812     }
11813
11814     defwndproc_counter++;
11815     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
11816     defwndproc_counter--;
11817
11818     return ret;
11819 }
11820
11821 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
11822                                int caret_index, int top_index, int line)
11823 {
11824     LRESULT ret;
11825
11826     /* calling an orig proc helps to avoid unnecessary message logging */
11827     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
11828     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
11829     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
11830     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
11831     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
11832     ok_(__FILE__, line)(ret == caret_index ||
11833                         broken(cur_sel == -1 && caret_index == 0 && ret == -1),  /* nt4 */
11834                         "expected caret index %d, got %ld\n", caret_index, ret);
11835     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
11836     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
11837 }
11838
11839 static void test_listbox_messages(void)
11840 {
11841     HWND parent, listbox;
11842     LRESULT ret;
11843
11844     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
11845                              100, 100, 200, 200, 0, 0, 0, NULL);
11846     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
11847                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
11848                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
11849     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
11850
11851     check_lb_state(listbox, 0, LB_ERR, 0, 0);
11852
11853     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
11854     ok(ret == 0, "expected 0, got %ld\n", ret);
11855     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
11856     ok(ret == 1, "expected 1, got %ld\n", ret);
11857     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
11858     ok(ret == 2, "expected 2, got %ld\n", ret);
11859
11860     check_lb_state(listbox, 3, LB_ERR, 0, 0);
11861
11862     flush_sequence();
11863
11864     log_all_parent_messages++;
11865
11866     trace("selecting item 0\n");
11867     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
11868     ok(ret == 0, "expected 0, got %ld\n", ret);
11869     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
11870     check_lb_state(listbox, 3, 0, 0, 0);
11871     flush_sequence();
11872
11873     trace("selecting item 1\n");
11874     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
11875     ok(ret == 1, "expected 1, got %ld\n", ret);
11876     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
11877     check_lb_state(listbox, 3, 1, 1, 0);
11878
11879     trace("selecting item 2\n");
11880     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
11881     ok(ret == 2, "expected 2, got %ld\n", ret);
11882     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
11883     check_lb_state(listbox, 3, 2, 2, 0);
11884
11885     trace("clicking on item 0\n");
11886     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
11887     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11888     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
11889     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
11890     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
11891     check_lb_state(listbox, 3, 0, 0, 0);
11892     flush_sequence();
11893
11894     trace("deleting item 0\n");
11895     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11896     ok(ret == 2, "expected 2, got %ld\n", ret);
11897     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11898     check_lb_state(listbox, 2, -1, 0, 0);
11899     flush_sequence();
11900
11901     trace("deleting item 0\n");
11902     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11903     ok(ret == 1, "expected 1, got %ld\n", ret);
11904     ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
11905     check_lb_state(listbox, 1, -1, 0, 0);
11906     flush_sequence();
11907
11908     trace("deleting item 0\n");
11909     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11910     ok(ret == 0, "expected 0, got %ld\n", ret);
11911     ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
11912     check_lb_state(listbox, 0, -1, 0, 0);
11913     flush_sequence();
11914
11915     trace("deleting item 0\n");
11916     ret = SendMessage(listbox, LB_DELETESTRING, 0, 0);
11917     ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
11918     check_lb_state(listbox, 0, -1, 0, 0);
11919     flush_sequence();
11920
11921     log_all_parent_messages--;
11922
11923     DestroyWindow(listbox);
11924     DestroyWindow(parent);
11925 }
11926
11927 /*************************** Menu test ******************************/
11928 static const struct message wm_popup_menu_1[] =
11929 {
11930     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11931     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11932     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
11933     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11934     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11935     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11936     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11937     { WM_INITMENU, sent|lparam, 0, 0 },
11938     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11939     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11940     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11941     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11942     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11943     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11944     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
11945     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11946     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11947     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11948     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11949     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11950     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11951     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11952     { 0 }
11953 };
11954 static const struct message wm_popup_menu_2[] =
11955 {
11956     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11957     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11958     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11959     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11960     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11961     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11962     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11963     { WM_INITMENU, sent|lparam, 0, 0 },
11964     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11965     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11966     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11967     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11968     { HCBT_CREATEWND, hook },
11969     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11970                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11971     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11972     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11973     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11974     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11975     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11976     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11977     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11978     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11979     { HCBT_DESTROYWND, hook },
11980     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11981     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11982     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11983     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11984     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11985     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11986     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11987     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11988     { 0 }
11989 };
11990 static const struct message wm_popup_menu_3[] =
11991 {
11992     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11993     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11994     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11995     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11996     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11997     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11998     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11999     { WM_INITMENU, sent|lparam, 0, 0 },
12000     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
12001     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
12002     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
12003     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
12004     { HCBT_CREATEWND, hook },
12005     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
12006                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
12007     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
12008     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
12009     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
12010     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
12011     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
12012     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
12013     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
12014     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
12015     { HCBT_DESTROYWND, hook },
12016     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12017     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
12018     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
12019     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12020     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12021     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
12022     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
12023     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
12024     { 0 }
12025 };
12026
12027 static const struct message wm_single_menu_item[] =
12028 {
12029     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
12030     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
12031     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
12032     { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
12033     { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
12034     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
12035     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
12036     { WM_INITMENU, sent|lparam, 0, 0 },
12037     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
12038     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
12039     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
12040     { WM_MENUCOMMAND, sent },
12041     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
12042     { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
12043     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
12044     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
12045
12046     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
12047     { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
12048     { WM_CHAR,  sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
12049     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
12050     { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
12051     { 0 }
12052 };
12053
12054 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12055 {
12056     if (message == WM_ENTERIDLE ||
12057         message == WM_INITMENU ||
12058         message == WM_INITMENUPOPUP ||
12059         message == WM_MENUSELECT ||
12060         message == WM_PARENTNOTIFY ||
12061         message == WM_ENTERMENULOOP ||
12062         message == WM_EXITMENULOOP ||
12063         message == WM_UNINITMENUPOPUP ||
12064         message == WM_KEYDOWN ||
12065         message == WM_KEYUP ||
12066         message == WM_CHAR ||
12067         message == WM_SYSKEYDOWN ||
12068         message == WM_SYSKEYUP ||
12069         message == WM_SYSCHAR ||
12070         message == WM_COMMAND ||
12071         message == WM_MENUCOMMAND)
12072     {
12073         struct recvd_message msg;
12074
12075         msg.hwnd = hwnd;
12076         msg.message = message;
12077         msg.flags = sent|wparam|lparam;
12078         msg.wParam = wp;
12079         msg.lParam = lp;
12080         msg.descr = "parent_menu_proc";
12081         add_message(&msg);
12082     }
12083
12084     return DefWindowProcA(hwnd, message, wp, lp);
12085 }
12086
12087 static void set_menu_style(HMENU hmenu, DWORD style)
12088 {
12089     MENUINFO mi;
12090     BOOL ret;
12091
12092     mi.cbSize = sizeof(mi);
12093     mi.fMask = MIM_STYLE;
12094     mi.dwStyle = style;
12095     SetLastError(0xdeadbeef);
12096     ret = pSetMenuInfo(hmenu, &mi);
12097     ok(ret, "SetMenuInfo error %u\n", GetLastError());
12098 }
12099
12100 static DWORD get_menu_style(HMENU hmenu)
12101 {
12102     MENUINFO mi;
12103     BOOL ret;
12104
12105     mi.cbSize = sizeof(mi);
12106     mi.fMask = MIM_STYLE;
12107     mi.dwStyle = 0;
12108     SetLastError(0xdeadbeef);
12109     ret = pGetMenuInfo(hmenu, &mi);
12110     ok(ret, "GetMenuInfo error %u\n", GetLastError());
12111
12112     return mi.dwStyle;
12113 }
12114
12115 static void test_menu_messages(void)
12116 {
12117     MSG msg;
12118     WNDCLASSA cls;
12119     HMENU hmenu, hmenu_popup;
12120     HWND hwnd;
12121     DWORD style;
12122
12123     if (!pGetMenuInfo || !pSetMenuInfo)
12124     {
12125         win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
12126         return;
12127     }
12128     cls.style = 0;
12129     cls.lpfnWndProc = parent_menu_proc;
12130     cls.cbClsExtra = 0;
12131     cls.cbWndExtra = 0;
12132     cls.hInstance = GetModuleHandleA(0);
12133     cls.hIcon = 0;
12134     cls.hCursor = LoadCursorA(0, IDC_ARROW);
12135     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
12136     cls.lpszMenuName = NULL;
12137     cls.lpszClassName = "TestMenuClass";
12138     UnregisterClass(cls.lpszClassName, cls.hInstance);
12139     if (!RegisterClassA(&cls)) assert(0);
12140
12141     SetLastError(0xdeadbeef);
12142     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12143                            100, 100, 200, 200, 0, 0, 0, NULL);
12144     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
12145
12146     SetLastError(0xdeadbeef);
12147     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
12148     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
12149
12150     SetMenu(hwnd, hmenu);
12151     SetForegroundWindow( hwnd );
12152
12153     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
12154     style = get_menu_style(hmenu);
12155     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12156
12157     hmenu_popup = GetSubMenu(hmenu, 0);
12158     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12159     style = get_menu_style(hmenu_popup);
12160     ok(style == 0, "expected 0, got %u\n", style);
12161
12162     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12163     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12164     style = get_menu_style(hmenu_popup);
12165     ok(style == 0, "expected 0, got %u\n", style);
12166
12167     /* Alt+E, Enter */
12168     trace("testing a popup menu command\n");
12169     flush_sequence();
12170     keybd_event(VK_MENU, 0, 0, 0);
12171     keybd_event('E', 0, 0, 0);
12172     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
12173     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12174     keybd_event(VK_RETURN, 0, 0, 0);
12175     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12176     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12177     {
12178         TranslateMessage(&msg);
12179         DispatchMessage(&msg);
12180     }
12181     if (!sequence_cnt)  /* we didn't get any message */
12182     {
12183         skip( "queuing key events not supported\n" );
12184         goto done;
12185     }
12186     /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
12187     if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
12188     {
12189         win_skip( "menu tracking through VK_MENU not supported\n" );
12190         goto done;
12191     }
12192     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
12193
12194     /* Alt+F, Right, Enter */
12195     trace("testing submenu of a popup menu command\n");
12196     flush_sequence();
12197     keybd_event(VK_MENU, 0, 0, 0);
12198     keybd_event('F', 0, 0, 0);
12199     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12200     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12201     keybd_event(VK_RIGHT, 0, 0, 0);
12202     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12203     keybd_event(VK_RETURN, 0, 0, 0);
12204     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12205     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12206     {
12207         TranslateMessage(&msg);
12208         DispatchMessage(&msg);
12209     }
12210     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
12211
12212     trace("testing single menu item command\n");
12213     flush_sequence();
12214     keybd_event(VK_MENU, 0, 0, 0);
12215     keybd_event('Q', 0, 0, 0);
12216     keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
12217     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12218     keybd_event(VK_ESCAPE, 0, 0, 0);
12219     keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
12220     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12221     {
12222         TranslateMessage(&msg);
12223         DispatchMessage(&msg);
12224     }
12225     ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
12226
12227     set_menu_style(hmenu, 0);
12228     style = get_menu_style(hmenu);
12229     ok(style == 0, "expected 0, got %u\n", style);
12230
12231     hmenu_popup = GetSubMenu(hmenu, 0);
12232     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12233     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
12234     style = get_menu_style(hmenu_popup);
12235     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
12236
12237     hmenu_popup = GetSubMenu(hmenu_popup, 0);
12238     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
12239     style = get_menu_style(hmenu_popup);
12240     ok(style == 0, "expected 0, got %u\n", style);
12241
12242     /* Alt+F, Right, Enter */
12243     trace("testing submenu of a popup menu command\n");
12244     flush_sequence();
12245     keybd_event(VK_MENU, 0, 0, 0);
12246     keybd_event('F', 0, 0, 0);
12247     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
12248     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
12249     keybd_event(VK_RIGHT, 0, 0, 0);
12250     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
12251     keybd_event(VK_RETURN, 0, 0, 0);
12252     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
12253     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
12254     {
12255         TranslateMessage(&msg);
12256         DispatchMessage(&msg);
12257     }
12258     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
12259
12260 done:
12261     DestroyWindow(hwnd);
12262     DestroyMenu(hmenu);
12263 }
12264
12265
12266 static void test_paintingloop(void)
12267 {
12268     HWND hwnd;
12269
12270     paint_loop_done = 0;
12271     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
12272                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
12273                                 100, 100, 100, 100, 0, 0, 0, NULL );
12274     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
12275     ShowWindow(hwnd,SW_NORMAL);
12276     SetFocus(hwnd);
12277
12278     while (!paint_loop_done)
12279     {
12280         MSG msg;
12281         if (PeekMessageA(&msg, 0, 0, 0, 1))
12282         {
12283             TranslateMessage(&msg);
12284             DispatchMessage(&msg);
12285         }
12286     }
12287     DestroyWindow(hwnd);
12288 }
12289
12290 static void test_defwinproc(void)
12291 {
12292     HWND hwnd;
12293     MSG msg;
12294     int gotwmquit = FALSE;
12295     hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL);
12296     assert(hwnd);
12297     DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
12298     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
12299         if( msg.message == WM_QUIT) gotwmquit = TRUE;
12300         DispatchMessageA( &msg );
12301     }
12302     ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n");
12303     DestroyWindow( hwnd);
12304 }
12305
12306 #define clear_clipboard(hwnd)  clear_clipboard_(__LINE__, (hwnd))
12307 static void clear_clipboard_(int line, HWND hWnd)
12308 {
12309     BOOL succ;
12310     succ = OpenClipboard(hWnd);
12311     ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
12312     succ = EmptyClipboard();
12313     ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
12314     succ = CloseClipboard();
12315     ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
12316 }
12317
12318 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
12319 static void expect_HWND_(int line, HWND expected, HWND got)
12320 {
12321     ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
12322 }
12323
12324 static WNDPROC pOldViewerProc;
12325
12326 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
12327 {
12328     static BOOL recursion_guard;
12329
12330     if (message == WM_DRAWCLIPBOARD && !recursion_guard)
12331     {
12332         recursion_guard = TRUE;
12333         clear_clipboard(hWnd);
12334         recursion_guard = FALSE;
12335     }
12336     return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
12337 }
12338
12339 static void test_clipboard_viewers(void)
12340 {
12341     static struct message wm_change_cb_chain[] =
12342     {
12343         { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
12344         { 0 }
12345     };
12346     static const struct message wm_clipboard_destroyed[] =
12347     {
12348         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12349         { 0 }
12350     };
12351     static struct message wm_clipboard_changed[] =
12352     {
12353         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12354         { 0 }
12355     };
12356     static struct message wm_clipboard_changed_and_owned[] =
12357     {
12358         { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
12359         { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
12360         { 0 }
12361     };
12362
12363     HINSTANCE hInst = GetModuleHandleA(NULL);
12364     HWND hWnd1, hWnd2, hWnd3;
12365     HWND hOrigViewer;
12366     HWND hRet;
12367
12368     hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
12369         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12370         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12371         GetDesktopWindow(), NULL, hInst, NULL);
12372     hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
12373         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12374         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12375         GetDesktopWindow(), NULL, hInst, NULL);
12376     hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
12377         WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
12378         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
12379         GetDesktopWindow(), NULL, hInst, NULL);
12380     trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
12381     assert(hWnd1 && hWnd2 && hWnd3);
12382
12383     flush_sequence();
12384
12385     /* Test getting the clipboard viewer and setting the viewer to NULL. */
12386     hOrigViewer = GetClipboardViewer();
12387     hRet = SetClipboardViewer(NULL);
12388     ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
12389     expect_HWND(hOrigViewer, hRet);
12390     expect_HWND(NULL, GetClipboardViewer());
12391
12392     /* Test registering hWnd1 as a viewer. */
12393     hRet = SetClipboardViewer(hWnd1);
12394     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12395     ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
12396     expect_HWND(NULL, hRet);
12397     expect_HWND(hWnd1, GetClipboardViewer());
12398
12399     /* Test that changing the clipboard actually refreshes the registered viewer. */
12400     clear_clipboard(hWnd1);
12401     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12402     ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
12403
12404     /* Again, but with different owner. */
12405     clear_clipboard(hWnd2);
12406     wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
12407     ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
12408
12409     /* Test re-registering same window. */
12410     hRet = SetClipboardViewer(hWnd1);
12411     wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
12412     ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
12413     expect_HWND(hWnd1, hRet);
12414     expect_HWND(hWnd1, GetClipboardViewer());
12415
12416     /* Test ChangeClipboardChain. */
12417     ChangeClipboardChain(hWnd2, hWnd3);
12418     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12419     wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
12420     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
12421     expect_HWND(hWnd1, GetClipboardViewer());
12422
12423     ChangeClipboardChain(hWnd2, NULL);
12424     wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
12425     wm_change_cb_chain[0].lParam = 0;
12426     ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
12427     expect_HWND(hWnd1, GetClipboardViewer());
12428
12429     ChangeClipboardChain(NULL, hWnd2);
12430     ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE);
12431     expect_HWND(hWnd1, GetClipboardViewer());
12432
12433     /* Actually change clipboard viewer with ChangeClipboardChain. */
12434     ChangeClipboardChain(hWnd1, hWnd2);
12435     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
12436     expect_HWND(hWnd2, GetClipboardViewer());
12437
12438     /* Test that no refresh messages are sent when viewer has unregistered. */
12439     clear_clipboard(hWnd2);
12440     ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
12441
12442     /* Register hWnd1 again. */
12443     ChangeClipboardChain(hWnd2, hWnd1);
12444     ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
12445     expect_HWND(hWnd1, GetClipboardViewer());
12446
12447     /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
12448      * changes the clipboard. When this happens, the system shouldn't send
12449      * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
12450      */
12451     pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
12452     clear_clipboard(hWnd2);
12453     /* The clipboard owner is changed in recursive_viewer_proc: */
12454     wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
12455     ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
12456
12457     /* Test unregistering. */
12458     ChangeClipboardChain(hWnd1, NULL);
12459     ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
12460     expect_HWND(NULL, GetClipboardViewer());
12461
12462     clear_clipboard(hWnd1);
12463     ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
12464
12465     DestroyWindow(hWnd1);
12466     DestroyWindow(hWnd2);
12467     DestroyWindow(hWnd3);
12468     SetClipboardViewer(hOrigViewer);
12469 }
12470
12471 static void test_PostMessage(void)
12472 {
12473     static const struct
12474     {
12475         HWND hwnd;
12476         BOOL ret;
12477     } data[] =
12478     {
12479         { HWND_TOP /* 0 */, TRUE },
12480         { HWND_BROADCAST, TRUE },
12481         { HWND_BOTTOM, TRUE },
12482         { HWND_TOPMOST, TRUE },
12483         { HWND_NOTOPMOST, FALSE },
12484         { HWND_MESSAGE, FALSE },
12485         { (HWND)0xdeadbeef, FALSE }
12486     };
12487     int i;
12488     HWND hwnd;
12489     BOOL ret;
12490     MSG msg;
12491     static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
12492
12493     SetLastError(0xdeadbeef);
12494     hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
12495     if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
12496     {
12497         win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
12498         return;
12499     }
12500     assert(hwnd);
12501
12502     flush_events();
12503
12504     PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678);
12505     PostMessage(0, WM_USER+2, 0x5678, 0x1234);
12506
12507     for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
12508     {
12509         memset(&msg, 0xab, sizeof(msg));
12510         ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
12511         ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
12512         if (data[i].ret)
12513         {
12514             if (data[i].hwnd)
12515                 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
12516                    msg.wParam == 0x5678 && msg.lParam == 0x1234,
12517                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
12518                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
12519             else
12520                 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
12521                    msg.wParam == 0x1234 && msg.lParam == 0x5678,
12522                    "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
12523                    i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
12524         }
12525     }
12526
12527     DestroyWindow(hwnd);
12528     flush_events();
12529 }
12530
12531 static const struct
12532 {
12533     DWORD exp, broken;
12534     BOOL todo;
12535 } wait_idle_expect[] =
12536 {
12537 /* 0 */  { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12538          { WAIT_TIMEOUT, 0,            FALSE },
12539          { WAIT_TIMEOUT, 0,            FALSE },
12540          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12541          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12542 /* 5 */  { WAIT_TIMEOUT, 0,            FALSE },
12543          { WAIT_TIMEOUT, 0,            FALSE },
12544          { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
12545          { 0,            0,            FALSE },
12546          { 0,            0,            FALSE },
12547 /* 10 */ { 0,            0,            FALSE },
12548          { 0,            0,            FALSE },
12549          { 0,            WAIT_TIMEOUT, FALSE },
12550          { 0,            0,            FALSE },
12551          { 0,            0,            FALSE },
12552 /* 15 */ { 0,            0,            FALSE },
12553          { WAIT_TIMEOUT, 0,            FALSE },
12554          { WAIT_TIMEOUT, 0,            FALSE },
12555          { WAIT_TIMEOUT, 0,            FALSE },
12556          { WAIT_TIMEOUT, 0,            FALSE },
12557 /* 20 */ { WAIT_TIMEOUT, 0,            FALSE },
12558 };
12559
12560 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
12561 {
12562     MSG msg;
12563
12564     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12565     Sleep( 200 );
12566     MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12567     return 0;
12568 }
12569
12570 static void do_wait_idle_child( int arg )
12571 {
12572     WNDCLASS cls;
12573     MSG msg;
12574     HWND hwnd = 0;
12575     HANDLE thread;
12576     DWORD id;
12577     HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
12578     HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
12579
12580     memset( &cls, 0, sizeof(cls) );
12581     cls.lpfnWndProc   = DefWindowProc;
12582     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12583     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12584     cls.lpszClassName = "TestClass";
12585     RegisterClass( &cls );
12586
12587     PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );  /* create the msg queue */
12588
12589     ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
12590     ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
12591
12592     switch (arg)
12593     {
12594     case 0:
12595         SetEvent( start_event );
12596         break;
12597     case 1:
12598         SetEvent( start_event );
12599         Sleep( 200 );
12600         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12601         break;
12602     case 2:
12603         SetEvent( start_event );
12604         Sleep( 200 );
12605         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12606         PostThreadMessage( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
12607         PeekMessage( &msg, 0, 0, 0, PM_REMOVE );
12608         break;
12609     case 3:
12610         SetEvent( start_event );
12611         Sleep( 200 );
12612         SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
12613         break;
12614     case 4:
12615         SetEvent( start_event );
12616         Sleep( 200 );
12617         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12618         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12619         break;
12620     case 5:
12621         SetEvent( start_event );
12622         Sleep( 200 );
12623         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12624         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12625         break;
12626     case 6:
12627         SetEvent( start_event );
12628         Sleep( 200 );
12629         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12630         while (PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ))
12631         {
12632             GetMessage( &msg, 0, 0, 0 );
12633             DispatchMessage( &msg );
12634         }
12635         break;
12636     case 7:
12637         SetEvent( start_event );
12638         Sleep( 200 );
12639         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12640         SetTimer( hwnd, 3, 1, NULL );
12641         Sleep( 200 );
12642         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessage( &msg );
12643         break;
12644     case 8:
12645         SetEvent( start_event );
12646         Sleep( 200 );
12647         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12648         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12649         break;
12650     case 9:
12651         SetEvent( start_event );
12652         Sleep( 200 );
12653         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12654         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12655         for (;;) GetMessage( &msg, 0, 0, 0 );
12656         break;
12657     case 10:
12658         SetEvent( start_event );
12659         Sleep( 200 );
12660         hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
12661         SetTimer( hwnd, 3, 1, NULL );
12662         Sleep( 200 );
12663         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
12664         break;
12665     case 11:
12666         SetEvent( start_event );
12667         Sleep( 200 );
12668         return;  /* exiting the process makes WaitForInputIdle return success too */
12669     case 12:
12670         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12671         Sleep( 200 );
12672         MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
12673         SetEvent( start_event );
12674         break;
12675     case 13:
12676         SetEvent( start_event );
12677         PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
12678         Sleep( 200 );
12679         thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
12680         WaitForSingleObject( thread, 10000 );
12681         CloseHandle( thread );
12682         break;
12683     case 14:
12684         SetEvent( start_event );
12685         Sleep( 200 );
12686         PeekMessage( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
12687         break;
12688     case 15:
12689         SetEvent( start_event );
12690         Sleep( 200 );
12691         PeekMessage( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
12692         break;
12693     case 16:
12694         SetEvent( start_event );
12695         Sleep( 200 );
12696         PeekMessage( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
12697         break;
12698     case 17:
12699         SetEvent( start_event );
12700         Sleep( 200 );
12701         PeekMessage( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
12702         break;
12703     case 18:
12704         SetEvent( start_event );
12705         Sleep( 200 );
12706         PeekMessage( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
12707         break;
12708     case 19:
12709         SetEvent( start_event );
12710         Sleep( 200 );
12711         PeekMessage( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
12712         break;
12713     case 20:
12714         SetEvent( start_event );
12715         Sleep( 200 );
12716         PeekMessage( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
12717         break;
12718     }
12719     WaitForSingleObject( end_event, 2000 );
12720     CloseHandle( start_event );
12721     CloseHandle( end_event );
12722     if (hwnd) DestroyWindow( hwnd );
12723 }
12724
12725 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
12726 {
12727     if (msg == WM_WININICHANGE) Sleep( 200 );  /* make sure the child waits */
12728     return DefWindowProcA( hwnd, msg, wp, lp );
12729 }
12730
12731 static DWORD CALLBACK wait_idle_thread( void *arg )
12732 {
12733     WNDCLASS cls;
12734     MSG msg;
12735     HWND hwnd;
12736
12737     memset( &cls, 0, sizeof(cls) );
12738     cls.lpfnWndProc   = wait_idle_proc;
12739     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
12740     cls.hCursor       = LoadCursor(0, IDC_ARROW);
12741     cls.lpszClassName = "TestClass";
12742     RegisterClass( &cls );
12743
12744     hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
12745     while (GetMessage( &msg, 0, 0, 0 )) DispatchMessage( &msg );
12746     DestroyWindow(hwnd);
12747     return 0;
12748 }
12749
12750 static void test_WaitForInputIdle( char *argv0 )
12751 {
12752     char path[MAX_PATH];
12753     PROCESS_INFORMATION pi;
12754     STARTUPINFOA startup;
12755     BOOL ret;
12756     HANDLE start_event, end_event, thread;
12757     unsigned int i;
12758     DWORD id;
12759     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
12760     const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
12761     BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
12762
12763     if (console_app)  /* build the test with -mwindows for better coverage */
12764         trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
12765
12766     start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
12767     end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
12768     ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
12769     ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
12770
12771     memset( &startup, 0, sizeof(startup) );
12772     startup.cb = sizeof(startup);
12773     startup.dwFlags = STARTF_USESHOWWINDOW;
12774     startup.wShowWindow = SW_SHOWNORMAL;
12775
12776     thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
12777
12778     for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
12779     {
12780         ResetEvent( start_event );
12781         ResetEvent( end_event );
12782         sprintf( path, "%s msg %u", argv0, i );
12783         ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
12784         ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
12785         if (ret)
12786         {
12787             ret = WaitForSingleObject( start_event, 5000 );
12788             ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
12789             if (ret == WAIT_OBJECT_0)
12790             {
12791                 ret = WaitForInputIdle( pi.hProcess, 1000 );
12792                 if (ret == WAIT_FAILED)
12793                     ok( console_app ||
12794                         ret == wait_idle_expect[i].exp ||
12795                         broken(ret == wait_idle_expect[i].broken),
12796                         "%u: WaitForInputIdle error %08x expected %08x\n",
12797                         i, ret, wait_idle_expect[i].exp );
12798                 else if (wait_idle_expect[i].todo)
12799                     todo_wine
12800                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12801                         "%u: WaitForInputIdle error %08x expected %08x\n",
12802                         i, ret, wait_idle_expect[i].exp );
12803                 else
12804                     ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
12805                         "%u: WaitForInputIdle error %08x expected %08x\n",
12806                         i, ret, wait_idle_expect[i].exp );
12807                 SetEvent( end_event );
12808                 WaitForSingleObject( pi.hProcess, 1000 );  /* give it a chance to exit on its own */
12809             }
12810             TerminateProcess( pi.hProcess, 0 );  /* just in case */
12811             winetest_wait_child_process( pi.hProcess );
12812             ret = WaitForInputIdle( pi.hProcess, 100 );
12813             ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
12814             CloseHandle( pi.hProcess );
12815             CloseHandle( pi.hThread );
12816         }
12817     }
12818     CloseHandle( start_event );
12819     PostThreadMessage( id, WM_QUIT, 0, 0 );
12820     WaitForSingleObject( thread, 10000 );
12821     CloseHandle( thread );
12822 }
12823
12824 static const struct message WmSetParentSeq_1[] = {
12825     { WM_SHOWWINDOW, sent|wparam, 0 },
12826     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12827     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12828     { WM_CHILDACTIVATE, sent },
12829     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
12830     { WM_MOVE, sent|defwinproc|wparam, 0 },
12831     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12832     { WM_SHOWWINDOW, sent|wparam, 1 },
12833     { 0 }
12834 };
12835
12836 static const struct message WmSetParentSeq_2[] = {
12837     { WM_SHOWWINDOW, sent|wparam, 0 },
12838     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12839     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
12840     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12841     { HCBT_SETFOCUS, hook|optional },
12842     { WM_NCACTIVATE, sent|wparam, 0 },
12843     { WM_ACTIVATE, sent|wparam, 0 },
12844     { WM_ACTIVATEAPP, sent|wparam, 0 },
12845     { WM_KILLFOCUS, sent|wparam, 0 },
12846     { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12847     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
12848     { HCBT_ACTIVATE, hook },
12849     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
12850     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
12851     { WM_NCACTIVATE, sent|wparam, 1 },
12852     { WM_ACTIVATE, sent|wparam, 1 },
12853     { HCBT_SETFOCUS, hook },
12854     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12855     { WM_SETFOCUS, sent|defwinproc },
12856     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
12857     { WM_MOVE, sent|defwinproc|wparam, 0 },
12858     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12859     { WM_SHOWWINDOW, sent|wparam, 1 },
12860     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12861     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
12862     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12863     { 0 }
12864 };
12865
12866
12867 static void test_SetParent(void)
12868 {
12869     HWND parent1, parent2, child, popup;
12870     RECT rc, rc_old;
12871
12872     parent1 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
12873                             100, 100, 200, 200, 0, 0, 0, NULL);
12874     ok(parent1 != 0, "Failed to create parent1 window\n");
12875
12876     parent2 = CreateWindowEx(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
12877                             400, 100, 200, 200, 0, 0, 0, NULL);
12878     ok(parent2 != 0, "Failed to create parent2 window\n");
12879
12880     /* WS_CHILD window */
12881     child = CreateWindowEx(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
12882                            10, 10, 150, 150, parent1, 0, 0, NULL);
12883     ok(child != 0, "Failed to create child window\n");
12884
12885     GetWindowRect(parent1, &rc);
12886     trace("parent1 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12887     GetWindowRect(child, &rc_old);
12888     MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
12889     trace("child (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
12890
12891     flush_sequence();
12892
12893     SetParent(child, parent2);
12894     flush_events();
12895     ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
12896
12897     ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
12898     ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
12899
12900     GetWindowRect(parent2, &rc);
12901     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12902     GetWindowRect(child, &rc);
12903     MapWindowPoints(0, parent2, (POINT *)&rc, 2);
12904     trace("child (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12905
12906     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
12907        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
12908        rc.left, rc.top, rc.right, rc.bottom );
12909
12910     /* WS_POPUP window */
12911     popup = CreateWindowEx(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
12912                            20, 20, 100, 100, 0, 0, 0, NULL);
12913     ok(popup != 0, "Failed to create popup window\n");
12914
12915     GetWindowRect(popup, &rc_old);
12916     trace("popup (%d,%d)-(%d,%d)\n", rc_old.left, rc_old.top, rc_old.right, rc_old.bottom);
12917
12918     flush_sequence();
12919
12920     SetParent(popup, child);
12921     flush_events();
12922     ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
12923
12924     ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
12925     ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
12926
12927     GetWindowRect(child, &rc);
12928     trace("parent2 (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12929     GetWindowRect(popup, &rc);
12930     MapWindowPoints(0, child, (POINT *)&rc, 2);
12931     trace("popup (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
12932
12933     ok(EqualRect(&rc_old, &rc), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
12934        rc_old.left, rc_old.top, rc_old.right, rc_old.bottom,
12935        rc.left, rc.top, rc.right, rc.bottom );
12936
12937     DestroyWindow(popup);
12938     DestroyWindow(child);
12939     DestroyWindow(parent1);
12940     DestroyWindow(parent2);
12941
12942     flush_sequence();
12943 }
12944
12945 static const struct message WmKeyReleaseOnly[] = {
12946     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
12947     { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
12948     { 0 }
12949 };
12950 static const struct message WmKeyPressNormal[] = {
12951     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
12952     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
12953     { 0 }
12954 };
12955 static const struct message WmKeyPressRepeat[] = {
12956     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
12957     { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
12958     { 0 }
12959 };
12960 static const struct message WmKeyReleaseNormal[] = {
12961     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
12962     { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
12963     { 0 }
12964 };
12965
12966 static void test_keyflags(void)
12967 {
12968     HWND test_window;
12969     SHORT key_state;
12970     BYTE keyboard_state[256];
12971     MSG msg;
12972
12973     test_window = CreateWindowEx(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12974                            100, 100, 200, 200, 0, 0, 0, NULL);
12975
12976     flush_sequence();
12977
12978     /* keyup without a keydown */
12979     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
12980     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
12981         DispatchMessage(&msg);
12982     ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
12983
12984     key_state = GetAsyncKeyState(0x41);
12985     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
12986
12987     key_state = GetKeyState(0x41);
12988     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
12989
12990     /* keydown */
12991     keybd_event(0x41, 0, 0, 0);
12992     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
12993         DispatchMessage(&msg);
12994     ok_sequence(WmKeyPressNormal, "key press only", FALSE);
12995
12996     key_state = GetAsyncKeyState(0x41);
12997     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
12998
12999     key_state = GetKeyState(0x41);
13000     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13001
13002     /* keydown repeat */
13003     keybd_event(0x41, 0, 0, 0);
13004     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13005         DispatchMessage(&msg);
13006     ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
13007
13008     key_state = GetAsyncKeyState(0x41);
13009     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13010
13011     key_state = GetKeyState(0x41);
13012     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13013
13014     /* keyup */
13015     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13016     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13017         DispatchMessage(&msg);
13018     ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
13019
13020     key_state = GetAsyncKeyState(0x41);
13021     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13022
13023     key_state = GetKeyState(0x41);
13024     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13025
13026     /* set the key state in this thread */
13027     GetKeyboardState(keyboard_state);
13028     keyboard_state[0x41] = 0x80;
13029     SetKeyboardState(keyboard_state);
13030
13031     key_state = GetAsyncKeyState(0x41);
13032     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13033
13034     /* keydown */
13035     keybd_event(0x41, 0, 0, 0);
13036     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13037         DispatchMessage(&msg);
13038     ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
13039
13040     key_state = GetAsyncKeyState(0x41);
13041     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13042
13043     key_state = GetKeyState(0x41);
13044     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13045
13046     /* clear the key state in this thread */
13047     GetKeyboardState(keyboard_state);
13048     keyboard_state[0x41] = 0;
13049     SetKeyboardState(keyboard_state);
13050
13051     key_state = GetAsyncKeyState(0x41);
13052     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13053
13054     /* keyup */
13055     keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
13056     while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
13057         DispatchMessage(&msg);
13058     ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
13059
13060     key_state = GetAsyncKeyState(0x41);
13061     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13062
13063     key_state = GetKeyState(0x41);
13064     ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
13065
13066     DestroyWindow(test_window);
13067     flush_sequence();
13068 }
13069
13070 static const struct message WmHotkeyPressLWIN[] = {
13071     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13072     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13073     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13074     { 0 }
13075 };
13076 static const struct message WmHotkeyPress[] = {
13077     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13078     { WM_HOTKEY, sent|wparam, 5 },
13079     { 0 }
13080 };
13081 static const struct message WmHotkeyRelease[] = {
13082     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13083     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
13084     { WM_KEYUP, sent|lparam, 0, 0x80000001 },
13085     { 0 }
13086 };
13087 static const struct message WmHotkeyReleaseLWIN[] = {
13088     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13089     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13090     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13091     { 0 }
13092 };
13093 static const struct message WmHotkeyCombined[] = {
13094     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13095     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13096     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13097     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13098     { WM_APP, sent, 0, 0 },
13099     { WM_HOTKEY, sent|wparam, 5 },
13100     { WM_APP+1, sent, 0, 0 },
13101     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13102     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13103     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13104     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13105     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13106     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13107     { 0 }
13108 };
13109 static const struct message WmHotkeyPrevious[] = {
13110     { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
13111     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13112     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13113     { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
13114     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
13115     { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
13116     { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
13117     { WM_KEYDOWN, sent|lparam, 0, 1 },
13118     { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
13119     { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
13120     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
13121     { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
13122     { 0 }
13123 };
13124 static const struct message WmHotkeyNew[] = {
13125     { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
13126     { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
13127     { WM_HOTKEY, sent|wparam, 5 },
13128     { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
13129     { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
13130     { 0 }
13131 };
13132
13133 static int hotkey_letter;
13134
13135 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
13136 {
13137     struct recvd_message msg;
13138
13139     if (nCode == HC_ACTION)
13140     {
13141         KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
13142
13143         msg.hwnd = 0;
13144         msg.message = wParam;
13145         msg.flags = kbd_hook|wparam|lparam;
13146         msg.wParam = kdbhookstruct->vkCode;
13147         msg.lParam = kdbhookstruct->flags;
13148         msg.descr = "KeyboardHookProc";
13149         add_message(&msg);
13150
13151         if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
13152         {
13153             ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
13154                "unexpected keycode %x\n", kdbhookstruct->vkCode);
13155        }
13156     }
13157
13158     return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
13159 }
13160
13161 static void test_hotkey(void)
13162 {
13163     HWND test_window, taskbar_window;
13164     BOOL ret;
13165     MSG msg;
13166     DWORD queue_status;
13167     SHORT key_state;
13168
13169     SetLastError(0xdeadbeef);
13170     ret = UnregisterHotKey(NULL, 0);
13171     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13172     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED, "unexpected error %d\n", GetLastError());
13173
13174     if (ret == TRUE)
13175     {
13176         skip("hotkeys not supported\n");
13177         return;
13178     }
13179
13180     test_window = CreateWindowEx(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13181                            100, 100, 200, 200, 0, 0, 0, NULL);
13182
13183     flush_sequence();
13184
13185     SetLastError(0xdeadbeef);
13186     ret = UnregisterHotKey(test_window, 0);
13187     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13188     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED, "unexpected error %d\n", GetLastError());
13189
13190     /* Search for a Windows Key + letter combination that hasn't been registered */
13191     for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
13192     {
13193         SetLastError(0xdeadbeef);
13194         ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13195
13196         if (ret == TRUE)
13197         {
13198             break;
13199         }
13200         else
13201         {
13202             ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED, "unexpected error %d\n", GetLastError());
13203         }
13204     }
13205
13206     if (hotkey_letter == 0x52)
13207     {
13208         ok(0, "Couldn't find any free Windows Key + letter combination\n");
13209         goto end;
13210     }
13211
13212     hKBD_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandle(NULL), 0);
13213     ok(hKBD_hook != NULL, "failed to install hook, err %i\n", GetLastError());
13214
13215     /* Same key combination, different id */
13216     SetLastError(0xdeadbeef);
13217     ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
13218     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13219     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED, "unexpected error %d\n", GetLastError());
13220
13221     /* Same key combination, different window */
13222     SetLastError(0xdeadbeef);
13223     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13224     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13225     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED, "unexpected error %d\n", GetLastError());
13226
13227     /* Register the same hotkey twice */
13228     SetLastError(0xdeadbeef);
13229     ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
13230     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13231     ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED, "unexpected error %d\n", GetLastError());
13232
13233     /* Window on another thread */
13234     taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
13235     if (!taskbar_window)
13236     {
13237         skip("no taskbar?\n");
13238     }
13239     else
13240     {
13241         SetLastError(0xdeadbeef);
13242         ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
13243         ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13244         ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD, "unexpected error %d\n", GetLastError());
13245     }
13246
13247     /* Inject the appropriate key sequence */
13248     keybd_event(VK_LWIN, 0, 0, 0);
13249     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13250         DispatchMessage(&msg);
13251     ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
13252
13253     keybd_event(hotkey_letter, 0, 0, 0);
13254     queue_status = GetQueueStatus(QS_HOTKEY);
13255     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13256     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13257     {
13258         if (msg.message == WM_HOTKEY)
13259         {
13260             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13261             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13262         }
13263         DispatchMessage(&msg);
13264     }
13265     ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
13266
13267     queue_status = GetQueueStatus(QS_HOTKEY);
13268     ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
13269
13270     key_state = GetAsyncKeyState(hotkey_letter);
13271     ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
13272
13273     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13274     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13275         DispatchMessage(&msg);
13276     ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
13277
13278     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13279     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13280         DispatchMessage(&msg);
13281     ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
13282
13283     /* normal posted WM_HOTKEY messages set QS_HOTKEY */
13284     PostMessage(test_window, WM_HOTKEY, 0, 0);
13285     queue_status = GetQueueStatus(QS_HOTKEY);
13286     ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
13287     queue_status = GetQueueStatus(QS_POSTMESSAGE);
13288     ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
13289     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13290         DispatchMessage(&msg);
13291     flush_sequence();
13292
13293     /* Send and process all messages at once */
13294     PostMessage(test_window, WM_APP, 0, 0);
13295     keybd_event(VK_LWIN, 0, 0, 0);
13296     keybd_event(hotkey_letter, 0, 0, 0);
13297     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13298     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13299
13300     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13301     {
13302         if (msg.message == WM_HOTKEY)
13303         {
13304             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13305             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13306         }
13307         DispatchMessage(&msg);
13308     }
13309     ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
13310
13311     /* Register same hwnd/id with different key combination */
13312     ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
13313     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13314
13315     /* Previous key combination does not work */
13316     keybd_event(VK_LWIN, 0, 0, 0);
13317     keybd_event(hotkey_letter, 0, 0, 0);
13318     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13319     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13320
13321     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13322         DispatchMessage(&msg);
13323     ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
13324
13325     /* New key combination works */
13326     keybd_event(hotkey_letter, 0, 0, 0);
13327     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13328
13329     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13330     {
13331         if (msg.message == WM_HOTKEY)
13332         {
13333             ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
13334             ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13335         }
13336         DispatchMessage(&msg);
13337     }
13338     ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
13339
13340     /* Unregister hotkey properly */
13341     ret = UnregisterHotKey(test_window, 5);
13342     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13343
13344     /* Unregister hotkey again */
13345     SetLastError(0xdeadbeef);
13346     ret = UnregisterHotKey(test_window, 5);
13347     ok(ret == FALSE, "expected FALSE, got %i\n", ret);
13348     ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED, "unexpected error %d\n", GetLastError());
13349
13350     /* Register thread hotkey */
13351     ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
13352     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13353
13354     /* Inject the appropriate key sequence */
13355     keybd_event(VK_LWIN, 0, 0, 0);
13356     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13357     {
13358         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13359         DispatchMessage(&msg);
13360     }
13361     ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
13362
13363     keybd_event(hotkey_letter, 0, 0, 0);
13364     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13365     {
13366         if (msg.message == WM_HOTKEY)
13367         {
13368             struct recvd_message message;
13369             ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
13370             ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
13371             message.message = msg.message;
13372             message.flags = sent|wparam|lparam;
13373             message.wParam = msg.wParam;
13374             message.lParam = msg.lParam;
13375             message.descr = "test_hotkey thread message";
13376             add_message(&message);
13377         }
13378         else
13379             ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13380         DispatchMessage(&msg);
13381     }
13382     ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
13383
13384     keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
13385     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13386     {
13387         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13388         DispatchMessage(&msg);
13389     }
13390     ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
13391
13392     keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
13393     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
13394     {
13395         ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
13396         DispatchMessage(&msg);
13397     }
13398     ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
13399
13400     /* Unregister thread hotkey */
13401     ret = UnregisterHotKey(NULL, 5);
13402     ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
13403
13404     UnhookWindowsHookEx(hKBD_hook);
13405     hKBD_hook = NULL;
13406
13407 end:
13408     UnregisterHotKey(NULL, 5);
13409     UnregisterHotKey(test_window, 5);
13410     DestroyWindow(test_window);
13411     flush_sequence();
13412 }
13413
13414 START_TEST(msg)
13415 {
13416     char **test_argv;
13417     BOOL ret;
13418     BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
13419     HMODULE hModuleImm32;
13420     BOOL (WINAPI *pImmDisableIME)(DWORD);
13421
13422     int argc = winetest_get_mainargs( &test_argv );
13423     if (argc >= 3)
13424     {
13425         unsigned int arg;
13426         /* Child process. */
13427         sscanf (test_argv[2], "%d", (unsigned int *) &arg);
13428         do_wait_idle_child( arg );
13429         return;
13430     }
13431
13432     init_procs();
13433
13434     hModuleImm32 = LoadLibrary("imm32.dll");
13435     if (hModuleImm32) {
13436         pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
13437         if (pImmDisableIME)
13438             pImmDisableIME(0);
13439     }
13440     pImmDisableIME = NULL;
13441     FreeLibrary(hModuleImm32);
13442
13443     if (!RegisterWindowClasses()) assert(0);
13444
13445     if (pSetWinEventHook)
13446     {
13447         hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
13448                                        GetModuleHandleA(0), win_event_proc,
13449                                        0, GetCurrentThreadId(),
13450                                        WINEVENT_INCONTEXT);
13451         if (pIsWinEventHookInstalled && hEvent_hook)
13452         {
13453             UINT event;
13454             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
13455                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
13456         }
13457     }
13458     if (!hEvent_hook) win_skip( "no win event hook support\n" );
13459
13460     cbt_hook_thread_id = GetCurrentThreadId();
13461     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
13462     if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
13463
13464     test_winevents();
13465
13466     /* Fix message sequences before removing 4 lines below */
13467 #if 1
13468     if (pUnhookWinEvent && hEvent_hook)
13469     {
13470         ret = pUnhookWinEvent(hEvent_hook);
13471         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
13472         pUnhookWinEvent = 0;
13473     }
13474     hEvent_hook = 0;
13475 #endif
13476
13477     test_SetParent();
13478     test_PostMessage();
13479     test_ShowWindow();
13480     test_PeekMessage();
13481     test_PeekMessage2();
13482     test_WaitForInputIdle( test_argv[0] );
13483     test_scrollwindowex();
13484     test_messages();
13485     test_setwindowpos();
13486     test_showwindow();
13487     invisible_parent_tests();
13488     test_mdi_messages();
13489     test_button_messages();
13490     test_static_messages();
13491     test_listbox_messages();
13492     test_combobox_messages();
13493     test_wmime_keydown_message();
13494     test_paint_messages();
13495     test_interthread_messages();
13496     test_message_conversion();
13497     test_accelerators();
13498     test_timers();
13499     test_timers_no_wnd();
13500     if (hCBT_hook) test_set_hook();
13501     test_DestroyWindow();
13502     test_DispatchMessage();
13503     test_SendMessageTimeout();
13504     test_edit_messages();
13505     test_quit_message();
13506     test_SetActiveWindow();
13507
13508     if (!pTrackMouseEvent)
13509         win_skip("TrackMouseEvent is not available\n");
13510     else
13511         test_TrackMouseEvent();
13512
13513     test_SetWindowRgn();
13514     test_sys_menu();
13515     test_dialog_messages();
13516     test_nullCallback();
13517     test_dbcs_wm_char();
13518     test_menu_messages();
13519     test_paintingloop();
13520     test_defwinproc();
13521     test_clipboard_viewers();
13522     test_keyflags();
13523     test_hotkey();
13524     /* keep it the last test, under Windows it tends to break the tests
13525      * which rely on active/foreground windows being correct.
13526      */
13527     test_SetForegroundWindow();
13528
13529     UnhookWindowsHookEx(hCBT_hook);
13530     if (pUnhookWinEvent && hEvent_hook)
13531     {
13532         ret = pUnhookWinEvent(hEvent_hook);
13533         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
13534         SetLastError(0xdeadbeef);
13535         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
13536         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
13537            GetLastError() == 0xdeadbeef, /* Win9x */
13538            "unexpected error %d\n", GetLastError());
13539     }
13540 }