winapi_test: Updated so the generated tests work.
[wine] / dlls / user32 / tests / msg.c
1 /*
2  * Unit tests for window message handling
3  *
4  * Copyright 1999 Ove Kaaven
5  * Copyright 2003 Dimitrie O. Paun
6  * Copyright 2004, 2005 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34
35 #include "wine/test.h"
36
37 #define MDI_FIRST_CHILD_ID 2004
38
39 /* undocumented SWP flags - from SDK 3.1 */
40 #define SWP_NOCLIENTSIZE        0x0800
41 #define SWP_NOCLIENTMOVE        0x1000
42 #define SWP_STATECHANGED        0x8000
43
44 #define SW_NORMALNA             0xCC    /* undoc. flag in MinMaximize */
45
46 #ifndef WM_KEYF1
47 #define WM_KEYF1 0x004d
48 #endif
49
50 #ifndef WM_SYSTIMER
51 #define WM_SYSTIMER         0x0118
52 #endif
53
54 #define WND_PARENT_ID           1
55 #define WND_POPUP_ID            2
56 #define WND_CHILD_ID            3
57
58 #ifndef WM_LBTRACKPOINT
59 #define WM_LBTRACKPOINT  0x0131
60 #endif
61
62 /* encoded DRAWITEMSTRUCT into an LPARAM */
63 typedef struct
64 {
65     union
66     {
67         struct
68         {
69             UINT type    : 4;  /* ODT_* flags */
70             UINT ctl_id  : 4;  /* Control ID */
71             UINT item_id : 4;  /* Menu item ID */
72             UINT action  : 4;  /* ODA_* flags */
73             UINT state   : 16; /* ODS_* flags */
74         } item;
75         LPARAM lp;
76     } u;
77 } DRAW_ITEM_STRUCT;
78
79 static BOOL test_DestroyWindow_flag;
80 static HWINEVENTHOOK hEvent_hook;
81
82 static void dump_winpos_flags(UINT flags);
83
84 static const WCHAR testWindowClassW[] =
85 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
86
87 /*
88 FIXME: add tests for these
89 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
90  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
91  WS_THICKFRAME: thick border
92  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
93  WS_BORDER (default for overlapped windows): single black border
94  none (default for child (and popup?) windows): no border
95 */
96
97 typedef enum {
98     sent=0x1,
99     posted=0x2,
100     parent=0x4,
101     wparam=0x8,
102     lparam=0x10,
103     defwinproc=0x20,
104     beginpaint=0x40,
105     optional=0x80,
106     hook=0x100,
107     winevent_hook=0x200
108 } msg_flags_t;
109
110 struct message {
111     UINT message;          /* the WM_* code */
112     msg_flags_t flags;     /* message props */
113     WPARAM wParam;         /* expected value of wParam */
114     LPARAM lParam;         /* expected value of lParam */
115 };
116
117 /* Empty message sequence */
118 static const struct message WmEmptySeq[] =
119 {
120     { 0 }
121 };
122 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
123 static const struct message WmCreateOverlappedSeq[] = {
124     { HCBT_CREATEWND, hook },
125     { WM_GETMINMAXINFO, sent },
126     { WM_NCCREATE, sent },
127     { WM_NCCALCSIZE, sent|wparam, 0 },
128     { 0x0093, sent|defwinproc|optional },
129     { 0x0094, sent|defwinproc|optional },
130     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
131     { WM_CREATE, sent },
132     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
133     { 0 }
134 };
135 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
136  * for a not visible overlapped window.
137  */
138 static const struct message WmSWP_ShowOverlappedSeq[] = {
139     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
140     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
141     { WM_NCPAINT, sent|wparam|optional, 1 },
142     { WM_GETTEXT, sent|defwinproc|optional },
143     { WM_ERASEBKGND, sent|optional },
144     { HCBT_ACTIVATE, hook },
145     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
146     { WM_NOTIFYFORMAT, sent|optional },
147     { WM_QUERYUISTATE, sent|optional },
148     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
149     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
150     { WM_ACTIVATEAPP, sent|wparam, 1 },
151     { WM_NCACTIVATE, sent|wparam, 1 },
152     { WM_GETTEXT, sent|defwinproc|optional },
153     { WM_ACTIVATE, sent|wparam, 1 },
154     { HCBT_SETFOCUS, hook },
155     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
156     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
157     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
158     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
159     { WM_GETTEXT, sent|optional },
160     { WM_NCPAINT, sent|wparam|optional, 1 },
161     { WM_GETTEXT, sent|defwinproc|optional },
162     { WM_ERASEBKGND, sent|optional },
163     /* Win9x adds SWP_NOZORDER below */
164     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
165     { WM_GETTEXT, sent|optional },
166     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
167     { WM_NCPAINT, sent|wparam|optional, 1 },
168     { WM_ERASEBKGND, sent|optional },
169     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
170     { WM_PAINT, sent|optional },
171     { WM_NCPAINT, sent|beginpaint|optional },
172     { WM_ERASEBKGND, sent|beginpaint|optional },
173     { 0 }
174 };
175 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
176  * for a visible overlapped window.
177  */
178 static const struct message WmSWP_HideOverlappedSeq[] = {
179     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
180     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
181     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
182     { 0 }
183 };
184
185 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
186  * for a visible overlapped window.
187  */
188 static const struct message WmSWP_ResizeSeq[] = {
189     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
190     { WM_GETMINMAXINFO, sent|defwinproc },
191     { WM_NCCALCSIZE, sent|wparam, TRUE },
192     { WM_NCPAINT, sent|optional },
193     { WM_GETTEXT, sent|defwinproc|optional },
194     { WM_ERASEBKGND, sent|optional },
195     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
196     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
197     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
198     { WM_NCPAINT, sent|optional },
199     { WM_GETTEXT, sent|defwinproc|optional },
200     { WM_ERASEBKGND, sent|optional },
201     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
202     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
203     { 0 }
204 };
205
206 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
207  * for a visible popup window.
208  */
209 static const struct message WmSWP_ResizePopupSeq[] = {
210     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
211     { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
212     { WM_NCCALCSIZE, sent|wparam, TRUE },
213     { WM_NCPAINT, sent|optional },
214     { WM_GETTEXT, sent|defwinproc|optional },
215     { WM_ERASEBKGND, sent|optional },
216     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
217     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
218     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
219     { WM_NCPAINT, sent|optional },
220     { WM_GETTEXT, sent|defwinproc|optional },
221     { WM_ERASEBKGND, sent|optional },
222     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
223     { 0 }
224 };
225
226 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
227  * for a visible overlapped window.
228  */
229 static const struct message WmSWP_MoveSeq[] = {
230     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
231     { WM_NCPAINT, sent|optional },
232     { WM_GETTEXT, sent|defwinproc|optional },
233     { WM_ERASEBKGND, sent|optional },
234     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
235     { WM_MOVE, sent|defwinproc|wparam, 0 },
236     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
237     { 0 }
238 };
239 /* Resize with SetWindowPos(SWP_NOZORDER)
240  * for a visible overlapped window
241  * SWP_NOZORDER is stripped by the logging code
242  */
243 static const struct message WmSWP_ResizeNoZOrder[] = {
244     { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
245     { WM_GETMINMAXINFO, sent|defwinproc },
246     { WM_NCCALCSIZE, sent|wparam, 1 },
247     { WM_NCPAINT, sent },
248     { WM_GETTEXT, sent|defwinproc|optional },
249     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
250     { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE },
251     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
252     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
253     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
254     { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
255     { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
256     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
257     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
258     { 0 }
259 };
260
261 /* Switch visible mdi children */
262 static const struct message WmSwitchChild[] = {
263     /* Switch MDI child */
264     { WM_MDIACTIVATE, sent },/* in the MDI client */
265     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
266     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
267     { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
268     /* Deactivate 2nd MDI child */
269     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
270     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
271     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
272     /* Preparing for maximize and maximaze the 1st MDI child */
273     { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
274     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
275     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
276     { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
277     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
278     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
279     /* Lock redraw 2nd MDI child */
280     { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
281     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
282     /* Restore 2nd MDI child */
283     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
284     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
285     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
286     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
287     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
288     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
289     /* Redraw 2nd MDI child */
290     { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
291     /* Redraw MDI frame */
292     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
293     { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
294     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
295     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
296     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
297     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
298     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
299     { HCBT_SETFOCUS, hook },
300     { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
301     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
302     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
303     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
304     { WM_SETFOCUS, sent },/* in the MDI client */
305     { HCBT_SETFOCUS, hook },
306     { WM_KILLFOCUS, sent },/* in the MDI client */
307     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
308     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
309     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
310     { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
311     { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
312     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
313     { 0 }
314 };
315
316 /* Switch visible not maximized mdi children */
317 static const struct message WmSwitchNotMaximizedChild[] = {
318     /* Switch not maximized MDI child */
319     { WM_MDIACTIVATE, sent },/* in the MDI client */
320     { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
321     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
322     { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
323     /* Deactivate 1st MDI child */
324     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
325     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
326     /* Activate 2nd MDI child */
327     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
328     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
329     { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
330     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
331     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
332     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
333     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
334     { HCBT_SETFOCUS, hook },
335     { WM_KILLFOCUS, sent }, /* in the  MDI client */
336     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
337     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
338     { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
339     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
340     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
341     { 0 }
342 };
343
344
345 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
346                 SWP_NOZORDER|SWP_FRAMECHANGED)
347  * for a visible overlapped window with WS_CLIPCHILDREN style set.
348  */
349 static const struct message WmSWP_FrameChanged_clip[] = {
350     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
351     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
352     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
353     { WM_GETTEXT, sent|parent|defwinproc|optional },
354     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
355     { WM_NCPAINT, sent }, /* wparam != 1 */
356     { WM_ERASEBKGND, sent },
357     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
358     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
359     { WM_PAINT, sent },
360     { 0 }
361 };
362 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
363                 SWP_NOZORDER|SWP_FRAMECHANGED)
364  * for a visible overlapped window.
365  */
366 static const struct message WmSWP_FrameChangedDeferErase[] = {
367     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
368     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
369     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
370     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
371     { WM_PAINT, sent|parent },
372     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
373     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
374     { WM_PAINT, sent },
375     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
376     { WM_ERASEBKGND, sent|beginpaint },
377     { 0 }
378 };
379
380 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
381                 SWP_NOZORDER|SWP_FRAMECHANGED)
382  * for a visible overlapped window without WS_CLIPCHILDREN style set.
383  */
384 static const struct message WmSWP_FrameChanged_noclip[] = {
385     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
386     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
387     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
388     { WM_GETTEXT, sent|parent|defwinproc|optional },
389     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
390     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
391     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
392     { WM_PAINT, sent },
393     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
394     { WM_ERASEBKGND, sent|beginpaint },
395     { 0 }
396 };
397
398 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
399 static const struct message WmShowOverlappedSeq[] = {
400     { WM_SHOWWINDOW, sent|wparam, 1 },
401     { WM_NCPAINT, sent|wparam|optional, 1 },
402     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
403     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
404     { WM_NCPAINT, sent|wparam|optional, 1 },
405     { WM_GETTEXT, sent|defwinproc|optional },
406     { WM_ERASEBKGND, sent|optional },
407     { HCBT_ACTIVATE, hook },
408     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
409     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
410     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
411     { WM_NCPAINT, sent|wparam|optional, 1 },
412     { WM_ACTIVATEAPP, sent|wparam, 1 },
413     { WM_NCACTIVATE, sent|wparam, 1 },
414     { WM_GETTEXT, sent|defwinproc|optional },
415     { WM_ACTIVATE, sent|wparam, 1 },
416     { HCBT_SETFOCUS, hook },
417     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
418     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
419     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
420     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
421     { WM_GETTEXT, sent|optional },
422     { WM_NCPAINT, sent|wparam|optional, 1 },
423     { WM_GETTEXT, sent|defwinproc|optional },
424     { WM_ERASEBKGND, sent|optional },
425     /* Win9x adds SWP_NOZORDER below */
426     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
427     { WM_NCCALCSIZE, sent|optional },
428     { WM_GETTEXT, sent|optional },
429     { WM_NCPAINT, sent|optional },
430     { WM_ERASEBKGND, sent|optional },
431 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
432        * messages. Does that mean that CreateWindow doesn't set initial
433        * window dimensions for overlapped windows?
434        */
435     { WM_SIZE, sent },
436     { WM_MOVE, sent },
437 #endif
438     { WM_PAINT, sent|optional },
439     { WM_NCPAINT, sent|beginpaint|optional },
440     { 0 }
441 };
442 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
443 static const struct message WmShowMaxOverlappedSeq[] = {
444     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
445     { WM_GETMINMAXINFO, sent },
446     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
447     { WM_GETMINMAXINFO, sent|defwinproc },
448     { WM_NCCALCSIZE, sent|wparam, TRUE },
449     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
450     { HCBT_ACTIVATE, hook },
451     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
452     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
453     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
454     { WM_ACTIVATEAPP, sent|wparam, 1 },
455     { WM_NCACTIVATE, sent|wparam, 1 },
456     { WM_GETTEXT, sent|defwinproc|optional },
457     { WM_ACTIVATE, sent|wparam, 1 },
458     { HCBT_SETFOCUS, hook },
459     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
460     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
461     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
462     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
463     { WM_GETTEXT, sent|optional },
464     { WM_NCPAINT, sent|wparam|optional, 1 },
465     { WM_GETTEXT, sent|defwinproc|optional },
466     { WM_ERASEBKGND, sent|optional },
467     /* Win9x adds SWP_NOZORDER below */
468     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
469     { WM_MOVE, sent|defwinproc },
470     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
471     { WM_GETTEXT, sent|optional },
472     { WM_NCCALCSIZE, sent|optional },
473     { WM_NCPAINT, sent|optional },
474     { WM_ERASEBKGND, sent|optional },
475     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
476     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
477     { WM_PAINT, sent|optional },
478     { WM_NCPAINT, sent|beginpaint|optional },
479     { WM_ERASEBKGND, sent|beginpaint|optional },
480     { 0 }
481 };
482 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
483 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
484     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
485     { WM_GETTEXT, sent|optional },
486     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
487     { WM_GETMINMAXINFO, sent|defwinproc },
488     { WM_NCCALCSIZE, sent|wparam, TRUE },
489     { WM_NCPAINT, sent|optional },
490     { WM_GETTEXT, sent|defwinproc|optional },
491     { WM_ERASEBKGND, sent|optional },
492     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
493     { WM_MOVE, sent|defwinproc|optional },
494     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
495     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
496     { WM_NCPAINT, sent|optional },
497     { WM_ERASEBKGND, sent|optional },
498     { WM_PAINT, sent|optional },
499     { WM_NCPAINT, sent|beginpaint|optional },
500     { WM_ERASEBKGND, sent|beginpaint|optional },
501     { 0 }
502 };
503 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
504 static const struct message WmShowRestoreMinOverlappedSeq[] = {
505     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
506     { WM_QUERYOPEN, sent|optional },
507     { WM_GETTEXT, sent|optional },
508     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
509     { WM_GETMINMAXINFO, sent|defwinproc },
510     { WM_NCCALCSIZE, sent|wparam, TRUE },
511     { HCBT_ACTIVATE, hook },
512     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
513     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
514     { WM_ACTIVATEAPP, sent|wparam, 1 },
515     { WM_NCACTIVATE, sent|wparam, 1 },
516     { WM_GETTEXT, sent|defwinproc|optional },
517     { WM_ACTIVATE, sent|wparam, 1 },
518     { HCBT_SETFOCUS, hook },
519     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
520     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
521     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
522     { WM_GETTEXT, sent|optional },
523     { WM_NCPAINT, sent|wparam|optional, 1 },
524     { WM_GETTEXT, sent|defwinproc|optional },
525     { WM_ERASEBKGND, sent },
526     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
527     { WM_MOVE, sent|defwinproc },
528     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
529     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
530     { WM_NCPAINT, sent|wparam|optional, 1 },
531     { WM_ERASEBKGND, sent|optional },
532     { WM_ACTIVATE, sent|wparam, 1 },
533     { WM_GETTEXT, sent|optional },
534     { WM_PAINT, sent|optional },
535     { WM_NCPAINT, sent|beginpaint|optional },
536     { WM_ERASEBKGND, sent|beginpaint|optional },
537     { 0 }
538 };
539 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
540 static const struct message WmShowMinOverlappedSeq[] = {
541     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
542     { HCBT_SETFOCUS, hook },
543     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
544     { WM_KILLFOCUS, sent },
545     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
546     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
547     { WM_GETTEXT, sent|optional },
548     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
549     { WM_GETMINMAXINFO, sent|defwinproc },
550     { WM_NCCALCSIZE, sent|wparam, TRUE },
551     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
552     { WM_NCPAINT, sent|optional },
553     { WM_GETTEXT, sent|defwinproc|optional },
554     { WM_WINDOWPOSCHANGED, sent },
555     { WM_MOVE, sent|defwinproc },
556     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
557     { WM_NCCALCSIZE, sent|optional },
558     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
559     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
560     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
561     { WM_NCACTIVATE, sent|wparam, 0 },
562     { WM_GETTEXT, sent|defwinproc|optional },
563     { WM_ACTIVATE, sent },
564     { WM_ACTIVATEAPP, sent|wparam, 0 },
565     { WM_PAINT, sent|optional },
566     { WM_NCPAINT, sent|beginpaint|optional },
567     { WM_ERASEBKGND, sent|beginpaint|optional },
568     { 0 }
569 };
570 /* ShowWindow(SW_HIDE) for a visible overlapped window */
571 static const struct message WmHideOverlappedSeq[] = {
572     { WM_SHOWWINDOW, sent|wparam, 0 },
573     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
574     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
575     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
576     { WM_SIZE, sent|optional }, /* XP doesn't send it */
577     { WM_MOVE, sent|optional }, /* XP doesn't send it */
578     { WM_NCACTIVATE, sent|wparam, 0 },
579     { WM_ACTIVATE, sent|wparam, 0 },
580     { WM_ACTIVATEAPP, sent|wparam, 0 },
581     { WM_KILLFOCUS, sent|wparam, 0 },
582     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
583     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
584     { 0 }
585 };
586 /* DestroyWindow for a visible overlapped window */
587 static const struct message WmDestroyOverlappedSeq[] = {
588     { HCBT_DESTROYWND, hook },
589     { 0x0090, sent|optional },
590     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
591     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
592     { 0x0090, sent|optional },
593     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
594     { WM_NCACTIVATE, sent|optional|wparam, 0 },
595     { WM_ACTIVATE, sent|optional|wparam, 0 },
596     { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
597     { WM_KILLFOCUS, sent|optional|wparam, 0 },
598     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
599     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
600     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
601     { WM_DESTROY, sent },
602     { WM_NCDESTROY, sent },
603     { 0 }
604 };
605 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
606 static const struct message WmCreateMaxPopupSeq[] = {
607     { HCBT_CREATEWND, hook },
608     { WM_NCCREATE, sent },
609     { WM_NCCALCSIZE, sent|wparam, 0 },
610     { WM_CREATE, sent },
611     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
612     { WM_SIZE, sent|wparam, SIZE_RESTORED },
613     { WM_MOVE, sent },
614     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
615     { WM_GETMINMAXINFO, sent },
616     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
617     { WM_NCCALCSIZE, sent|wparam, TRUE },
618     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
619     { WM_MOVE, sent|defwinproc },
620     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
621     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
622     { WM_SHOWWINDOW, sent|wparam, 1 },
623     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
624     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
625     { HCBT_ACTIVATE, hook },
626     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
627     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
628     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
629     { WM_NCPAINT, sent|wparam|optional, 1 },
630     { WM_ERASEBKGND, sent|optional },
631     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
632     { WM_ACTIVATEAPP, sent|wparam, 1 },
633     { WM_NCACTIVATE, sent|wparam, 1 },
634     { WM_ACTIVATE, sent|wparam, 1 },
635     { HCBT_SETFOCUS, hook },
636     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
637     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
638     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
639     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
640     { WM_GETTEXT, sent|optional },
641     { WM_SYNCPAINT, sent|wparam|optional, 4 },
642     { WM_NCPAINT, sent|wparam|optional, 1 },
643     { WM_ERASEBKGND, sent|optional },
644     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
645     { 0 }
646 };
647 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
648 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
649     { HCBT_CREATEWND, hook },
650     { WM_NCCREATE, sent },
651     { WM_NCCALCSIZE, sent|wparam, 0 },
652     { WM_CREATE, sent },
653     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
654     { WM_SIZE, sent|wparam, SIZE_RESTORED },
655     { WM_MOVE, sent },
656     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
657     { WM_GETMINMAXINFO, sent },
658     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED  },
659     { WM_NCCALCSIZE, sent|wparam, TRUE },
660     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
661     { WM_MOVE, sent|defwinproc },
662     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
663     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
664     { 0 }
665 };
666 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
667 static const struct message WmShowMaxPopupResizedSeq[] = {
668     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
669     { WM_GETMINMAXINFO, sent },
670     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
671     { WM_NCCALCSIZE, sent|wparam, TRUE },
672     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
673     { HCBT_ACTIVATE, hook },
674     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
675     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
676     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
677     { WM_ACTIVATEAPP, sent|wparam, 1 },
678     { WM_NCACTIVATE, sent|wparam, 1 },
679     { WM_ACTIVATE, sent|wparam, 1 },
680     { HCBT_SETFOCUS, hook },
681     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
682     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
683     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
684     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
685     { WM_GETTEXT, sent|optional },
686     { WM_NCPAINT, sent|wparam|optional, 1 },
687     { WM_ERASEBKGND, sent|optional },
688     { WM_WINDOWPOSCHANGED, sent },
689     /* WinNT4.0 sends WM_MOVE */
690     { WM_MOVE, sent|defwinproc|optional },
691     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
692     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
693     { 0 }
694 };
695 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
696 static const struct message WmShowMaxPopupSeq[] = {
697     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
698     { WM_GETMINMAXINFO, sent },
699     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
700     { WM_NCCALCSIZE, sent|wparam, TRUE },
701     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
702     { HCBT_ACTIVATE, hook },
703     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
704     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
705     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
706     { WM_ACTIVATEAPP, sent|wparam, 1 },
707     { WM_NCACTIVATE, sent|wparam, 1 },
708     { WM_ACTIVATE, sent|wparam, 1 },
709     { HCBT_SETFOCUS, hook },
710     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
711     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
712     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
713     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
714     { WM_GETTEXT, sent|optional },
715     { WM_SYNCPAINT, sent|wparam|optional, 4 },
716     { WM_NCPAINT, sent|wparam|optional, 1 },
717     { WM_ERASEBKGND, sent|optional },
718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
719     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
720     { 0 }
721 };
722 /* CreateWindow(WS_VISIBLE) for popup window */
723 static const struct message WmCreatePopupSeq[] = {
724     { HCBT_CREATEWND, hook },
725     { WM_NCCREATE, sent },
726     { WM_NCCALCSIZE, sent|wparam, 0 },
727     { WM_CREATE, sent },
728     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
729     { WM_SIZE, sent|wparam, SIZE_RESTORED },
730     { WM_MOVE, sent },
731     { WM_SHOWWINDOW, sent|wparam, 1 },
732     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
733     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
734     { HCBT_ACTIVATE, hook },
735     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
736     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
737     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
738     { WM_NCPAINT, sent|wparam|optional, 1 },
739     { WM_ERASEBKGND, sent|optional },
740     { WM_ACTIVATEAPP, sent|wparam, 1 },
741     { WM_NCACTIVATE, sent|wparam, 1 },
742     { WM_ACTIVATE, sent|wparam, 1 },
743     { HCBT_SETFOCUS, hook },
744     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
745     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
746     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
747     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
748     { WM_GETTEXT, sent|optional },
749     { WM_SYNCPAINT, sent|wparam|optional, 4 },
750     { WM_NCPAINT, sent|wparam|optional, 1 },
751     { WM_ERASEBKGND, sent|optional },
752     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
753     { 0 }
754 };
755 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
756 static const struct message WmShowVisMaxPopupSeq[] = {
757     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
758     { WM_GETMINMAXINFO, sent },
759     { WM_GETTEXT, sent|optional },
760     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
761     { WM_GETTEXT, sent|optional },
762     { WM_NCCALCSIZE, sent|wparam, TRUE },
763     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
764     { WM_NCPAINT, sent|wparam|optional, 1 },
765     { WM_ERASEBKGND, sent|optional },
766     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
767     { WM_MOVE, sent|defwinproc },
768     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
769     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
770     { 0 }
771 };
772 /* CreateWindow (for a child popup window, not initially visible) */
773 static const struct message WmCreateChildPopupSeq[] = {
774     { HCBT_CREATEWND, hook },
775     { WM_NCCREATE, sent }, 
776     { WM_NCCALCSIZE, sent|wparam, 0 },
777     { WM_CREATE, sent },
778     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
779     { WM_SIZE, sent|wparam, SIZE_RESTORED },
780     { WM_MOVE, sent },
781     { 0 }
782 };
783 /* CreateWindow (for a popup window, not initially visible,
784  * which sets WS_VISIBLE in WM_CREATE handler)
785  */
786 static const struct message WmCreateInvisiblePopupSeq[] = {
787     { HCBT_CREATEWND, hook },
788     { WM_NCCREATE, sent }, 
789     { WM_NCCALCSIZE, sent|wparam, 0 },
790     { WM_CREATE, sent },
791     { WM_STYLECHANGING, sent },
792     { WM_STYLECHANGED, sent },
793     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
794     { WM_SIZE, sent|wparam, SIZE_RESTORED },
795     { WM_MOVE, sent },
796     { 0 }
797 };
798 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
799  * for a popup window with WS_VISIBLE style set
800  */
801 static const struct message WmShowVisiblePopupSeq_2[] = {
802     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
803     { 0 }
804 };
805 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
806  * for a popup window with WS_VISIBLE style set
807  */
808 static const struct message WmShowVisiblePopupSeq_3[] = {
809     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
810     { HCBT_ACTIVATE, hook },
811     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
812     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
813     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
814     { WM_NCACTIVATE, sent|wparam, 1 },
815     { WM_ACTIVATE, sent|wparam, 1 },
816     { HCBT_SETFOCUS, hook },
817     { WM_KILLFOCUS, sent|parent },
818     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
819     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
820     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
821     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
822     { WM_SETFOCUS, sent|defwinproc },
823     { WM_GETTEXT, sent|optional },
824     { 0 }
825 };
826 /* CreateWindow (for child window, not initially visible) */
827 static const struct message WmCreateChildSeq[] = {
828     { HCBT_CREATEWND, hook },
829     { WM_NCCREATE, sent }, 
830     /* child is inserted into parent's child list after WM_NCCREATE returns */
831     { WM_NCCALCSIZE, sent|wparam, 0 },
832     { WM_CREATE, sent },
833     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
834     { WM_SIZE, sent|wparam, SIZE_RESTORED },
835     { WM_MOVE, sent },
836     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
837     { 0 }
838 };
839 /* CreateWindow (for maximized child window, not initially visible) */
840 static const struct message WmCreateMaximizedChildSeq[] = {
841     { HCBT_CREATEWND, hook },
842     { WM_NCCREATE, sent }, 
843     { WM_NCCALCSIZE, sent|wparam, 0 },
844     { WM_CREATE, sent },
845     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
846     { WM_SIZE, sent|wparam, SIZE_RESTORED },
847     { WM_MOVE, sent },
848     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
849     { WM_GETMINMAXINFO, sent },
850     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
851     { WM_NCCALCSIZE, sent|wparam, 1 },
852     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
853     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
854     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
855     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
856     { 0 }
857 };
858 /* CreateWindow (for a child window, initially visible) */
859 static const struct message WmCreateVisibleChildSeq[] = {
860     { HCBT_CREATEWND, hook },
861     { WM_NCCREATE, sent }, 
862     /* child is inserted into parent's child list after WM_NCCREATE returns */
863     { WM_NCCALCSIZE, sent|wparam, 0 },
864     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
865     { WM_CREATE, sent },
866     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
867     { WM_SIZE, sent|wparam, SIZE_RESTORED },
868     { WM_MOVE, sent },
869     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
870     { WM_SHOWWINDOW, sent|wparam, 1 },
871     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
872     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
873     { WM_ERASEBKGND, sent|parent|optional },
874     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
875     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
876     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
877     { 0 }
878 };
879 /* ShowWindow(SW_SHOW) for a not visible child window */
880 static const struct message WmShowChildSeq[] = {
881     { WM_SHOWWINDOW, sent|wparam, 1 },
882     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
883     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
884     { WM_ERASEBKGND, sent|parent|optional },
885     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
886     { 0 }
887 };
888 /* ShowWindow(SW_HIDE) for a visible child window */
889 static const struct message WmHideChildSeq[] = {
890     { WM_SHOWWINDOW, sent|wparam, 0 },
891     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
892     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
893     { WM_ERASEBKGND, sent|parent|optional },
894     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
895     { 0 }
896 };
897 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
898 static const struct message WmHideChildSeq2[] = {
899     { WM_SHOWWINDOW, sent|wparam, 0 },
900     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
901     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
902     { WM_ERASEBKGND, sent|parent },
903     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
904     { 0 }
905 };
906 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
907  * for a not visible child window
908  */
909 static const struct message WmShowChildSeq_2[] = {
910     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
911     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
912     { WM_CHILDACTIVATE, sent },
913     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
914     { 0 }
915 };
916 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
917  * for a not visible child window
918  */
919 static const struct message WmShowChildSeq_3[] = {
920     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
921     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
922     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
923     { 0 }
924 };
925 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
926  * for a visible child window with a caption
927  */
928 static const struct message WmShowChildSeq_4[] = {
929     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
930     { WM_CHILDACTIVATE, sent },
931     { 0 }
932 };
933 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
934 static const struct message WmShowChildInvisibleParentSeq_1[] = {
935     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
936     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
937     { WM_NCCALCSIZE, sent|wparam, 1 },
938     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
939     { WM_CHILDACTIVATE, sent|optional },
940     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
941     { WM_MOVE, sent|defwinproc },
942     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
943     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
944     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
945     /* FIXME: Wine creates an icon/title window while Windows doesn't */
946     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
947     { WM_GETTEXT, sent|optional },
948     { 0 }
949 };
950 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
951 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
952     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
953     { 0 }
954 };
955 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
956 static const struct message WmShowChildInvisibleParentSeq_2[] = {
957     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
958     { WM_GETMINMAXINFO, sent },
959     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
960     { WM_NCCALCSIZE, sent|wparam, 1 },
961     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
962     { WM_CHILDACTIVATE, sent },
963     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
964     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
965     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
966     { 0 }
967 };
968 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
969 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
970     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
971     { 0 }
972 };
973 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
974 static const struct message WmShowChildInvisibleParentSeq_3[] = {
975     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
976     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
977     { WM_NCCALCSIZE, sent|wparam, 1 },
978     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
979     { WM_CHILDACTIVATE, sent },
980     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
981     { WM_MOVE, sent|defwinproc },
982     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
983     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
984     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
985     /* FIXME: Wine creates an icon/title window while Windows doesn't */
986     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
987     { WM_GETTEXT, sent|optional },
988     { 0 }
989 };
990 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
991 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
992     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
993     { 0 }
994 };
995 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
996 static const struct message WmShowChildInvisibleParentSeq_4[] = {
997     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
998     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
999     { WM_NCCALCSIZE, sent|wparam, 1 },
1000     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1001     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1002     { WM_MOVE, sent|defwinproc },
1003     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
1004     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1005     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1006     /* FIXME: Wine creates an icon/title window while Windows doesn't */
1007     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1008     { WM_GETTEXT, sent|optional },
1009     { 0 }
1010 };
1011 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1012 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1013     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1014     { 0 }
1015 };
1016 /* ShowWindow(SW_SHOW) for child with invisible parent */
1017 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1018     { WM_SHOWWINDOW, sent|wparam, 1 },
1019     { 0 }
1020 };
1021 /* ShowWindow(SW_HIDE) for child with invisible parent */
1022 static const struct message WmHideChildInvisibleParentSeq[] = {
1023     { WM_SHOWWINDOW, sent|wparam, 0 },
1024     { 0 }
1025 };
1026 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1027 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1028     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1029     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1030     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1031     { 0 }
1032 };
1033 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1034 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1035     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1036     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1037     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1038     { 0 }
1039 };
1040 /* DestroyWindow for a visible child window */
1041 static const struct message WmDestroyChildSeq[] = {
1042     { HCBT_DESTROYWND, hook },
1043     { 0x0090, sent|optional },
1044     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1045     { WM_SHOWWINDOW, sent|wparam, 0 },
1046     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1047     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1048     { WM_ERASEBKGND, sent|parent|optional },
1049     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1050     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1051     { WM_KILLFOCUS, sent },
1052     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1053     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1054     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1055     { WM_SETFOCUS, sent|parent },
1056     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1057     { WM_DESTROY, sent },
1058     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1059     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1060     { WM_NCDESTROY, sent },
1061     { 0 }
1062 };
1063 /* DestroyWindow for a visible child window with invisible parent */
1064 static const struct message WmDestroyInvisibleChildSeq[] = {
1065     { HCBT_DESTROYWND, hook },
1066     { 0x0090, sent|optional },
1067     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1068     { WM_SHOWWINDOW, sent|wparam, 0 },
1069     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1070     { WM_DESTROY, sent },
1071     { WM_NCDESTROY, sent },
1072     { 0 }
1073 };
1074 /* Moving the mouse in nonclient area */
1075 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
1076     { WM_NCHITTEST, sent },
1077     { WM_SETCURSOR, sent },
1078     { WM_NCMOUSEMOVE, posted },
1079     { 0 }
1080 };
1081 /* Moving the mouse in client area */
1082 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
1083     { WM_NCHITTEST, sent },
1084     { WM_SETCURSOR, sent },
1085     { WM_MOUSEMOVE, posted },
1086     { 0 }
1087 };
1088 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1089 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
1090     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
1091     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
1092     { WM_GETMINMAXINFO, sent|defwinproc },
1093     { WM_ENTERSIZEMOVE, sent|defwinproc },
1094     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1095     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1096     { WM_MOVE, sent|defwinproc },
1097     { WM_EXITSIZEMOVE, sent|defwinproc },
1098     { 0 }
1099 };
1100 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
1101 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
1102     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
1103     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
1104     { WM_GETMINMAXINFO, sent|defwinproc },
1105     { WM_ENTERSIZEMOVE, sent|defwinproc },
1106     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
1107     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
1108     { WM_GETMINMAXINFO, sent|defwinproc },
1109     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1110     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
1111     { WM_GETTEXT, sent|defwinproc },
1112     { WM_ERASEBKGND, sent|defwinproc },
1113     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
1114     { WM_MOVE, sent|defwinproc },
1115     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1116     { WM_EXITSIZEMOVE, sent|defwinproc },
1117     { 0 }
1118 };
1119 /* Resizing child window with MoveWindow (32) */
1120 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1121     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1122     { WM_NCCALCSIZE, sent|wparam, 1 },
1123     { WM_ERASEBKGND, sent|parent|optional },
1124     { WM_ERASEBKGND, sent|optional },
1125     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1126     { WM_MOVE, sent|defwinproc },
1127     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1128     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1129     { 0 }
1130 };
1131 /* Clicking on inactive button */
1132 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
1133     { WM_NCHITTEST, sent },
1134     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
1135     { WM_MOUSEACTIVATE, sent },
1136     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
1137     { WM_SETCURSOR, sent },
1138     { WM_SETCURSOR, sent|parent|defwinproc },
1139     { WM_LBUTTONDOWN, posted },
1140     { WM_KILLFOCUS, posted|parent },
1141     { WM_SETFOCUS, posted },
1142     { WM_CTLCOLORBTN, posted|parent },
1143     { BM_SETSTATE, posted },
1144     { WM_CTLCOLORBTN, posted|parent },
1145     { WM_LBUTTONUP, posted },
1146     { BM_SETSTATE, posted },
1147     { WM_CTLCOLORBTN, posted|parent },
1148     { WM_COMMAND, posted|parent },
1149     { 0 }
1150 };
1151 /* Reparenting a button (16/32) */
1152 /* The last child (button) reparented gets topmost for its new parent. */
1153 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
1154     { WM_SHOWWINDOW, sent|wparam, 0 },
1155     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1156     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1157     { WM_ERASEBKGND, sent|parent },
1158     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1159     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
1160     { WM_CHILDACTIVATE, sent },
1161     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW },
1162     { WM_MOVE, sent|defwinproc },
1163     { WM_SHOWWINDOW, sent|wparam, 1 },
1164     { 0 }
1165 };
1166 /* Creation of a custom dialog (32) */
1167 static const struct message WmCreateCustomDialogSeq[] = {
1168     { HCBT_CREATEWND, hook },
1169     { WM_GETMINMAXINFO, sent },
1170     { WM_NCCREATE, sent },
1171     { WM_NCCALCSIZE, sent|wparam, 0 },
1172     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1173     { WM_CREATE, sent },
1174     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1175     { WM_NOTIFYFORMAT, sent|optional },
1176     { WM_QUERYUISTATE, sent|optional },
1177     { WM_WINDOWPOSCHANGING, sent|optional },
1178     { WM_GETMINMAXINFO, sent|optional },
1179     { WM_NCCALCSIZE, sent|optional },
1180     { WM_WINDOWPOSCHANGED, sent|optional },
1181     { WM_SHOWWINDOW, sent|wparam, 1 },
1182     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1183     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1184     { HCBT_ACTIVATE, hook },
1185     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1186
1187
1188     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1189
1190     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1191
1192     { WM_NCACTIVATE, sent|wparam, 1 },
1193     { WM_GETTEXT, sent|optional|defwinproc },
1194     { WM_GETTEXT, sent|optional|defwinproc },
1195     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1196     { WM_ACTIVATE, sent|wparam, 1 },
1197     { WM_GETTEXT, sent|optional },
1198     { WM_KILLFOCUS, sent|parent },
1199     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1200     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1201     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1202     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1203     { WM_SETFOCUS, sent },
1204     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1205     { WM_NCPAINT, sent|wparam, 1 },
1206     { WM_GETTEXT, sent|optional|defwinproc },
1207     { WM_GETTEXT, sent|optional|defwinproc },
1208     { WM_ERASEBKGND, sent },
1209     { WM_CTLCOLORDLG, sent|defwinproc },
1210     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1211     { WM_GETTEXT, sent|optional },
1212     { WM_GETTEXT, sent|optional },
1213     { WM_NCCALCSIZE, sent|optional },
1214     { WM_NCPAINT, sent|optional },
1215     { WM_GETTEXT, sent|optional|defwinproc },
1216     { WM_GETTEXT, sent|optional|defwinproc },
1217     { WM_ERASEBKGND, sent|optional },
1218     { WM_CTLCOLORDLG, sent|optional|defwinproc },
1219     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1220     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1221     { WM_MOVE, sent },
1222     { 0 }
1223 };
1224 /* Calling EndDialog for a custom dialog (32) */
1225 static const struct message WmEndCustomDialogSeq[] = {
1226     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1227     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1228     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1229     { WM_GETTEXT, sent|optional },
1230     { HCBT_ACTIVATE, hook },
1231     { WM_NCACTIVATE, sent|wparam, 0 },
1232     { WM_GETTEXT, sent|optional|defwinproc },
1233     { WM_GETTEXT, sent|optional|defwinproc },
1234     { WM_ACTIVATE, sent|wparam, 0 },
1235     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1236     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1237     { HCBT_SETFOCUS, hook },
1238     { WM_KILLFOCUS, sent },
1239     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1240     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1241     { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1242     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1243     { WM_SETFOCUS, sent|parent|defwinproc },
1244     { 0 }
1245 };
1246 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1247 static const struct message WmShowCustomDialogSeq[] = {
1248     { WM_SHOWWINDOW, sent|wparam, 1 },
1249     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1250     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1251     { HCBT_ACTIVATE, hook },
1252     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1253
1254     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1255
1256     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1257     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1258     { WM_NCACTIVATE, sent|wparam, 1 },
1259     { WM_ACTIVATE, sent|wparam, 1 },
1260     { WM_GETTEXT, sent|optional },
1261
1262     { WM_KILLFOCUS, sent|parent },
1263     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1264     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1265     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1266     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1267     { WM_SETFOCUS, sent },
1268     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1269     { WM_NCPAINT, sent|wparam, 1 },
1270     { WM_ERASEBKGND, sent },
1271     { WM_CTLCOLORDLG, sent|defwinproc },
1272     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1273     { 0 }
1274 };
1275 /* Creation and destruction of a modal dialog (32) */
1276 static const struct message WmModalDialogSeq[] = {
1277     { WM_CANCELMODE, sent|parent },
1278     { HCBT_SETFOCUS, hook },
1279     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1280     { WM_KILLFOCUS, sent|parent },
1281     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1282     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1283     { WM_ENABLE, sent|parent|wparam, 0 },
1284     { HCBT_CREATEWND, hook },
1285     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1286     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1287     { WM_SETFONT, sent },
1288     { WM_INITDIALOG, sent },
1289     { WM_CHANGEUISTATE, sent|optional },
1290     { WM_UPDATEUISTATE, sent|optional },
1291     { WM_SHOWWINDOW, sent },
1292     { HCBT_ACTIVATE, hook },
1293     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1294     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1295     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1296     { WM_NCACTIVATE, sent|wparam, 1 },
1297     { WM_GETTEXT, sent|optional },
1298     { WM_ACTIVATE, sent|wparam, 1 },
1299     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1300     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1301     { WM_NCPAINT, sent },
1302     { WM_GETTEXT, sent|optional },
1303     { WM_ERASEBKGND, sent },
1304     { WM_CTLCOLORDLG, sent },
1305     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1306     { WM_GETTEXT, sent|optional },
1307     { WM_NCCALCSIZE, sent|optional },
1308     { WM_NCPAINT, sent|optional },
1309     { WM_GETTEXT, sent|optional },
1310     { WM_ERASEBKGND, sent|optional },
1311     { WM_CTLCOLORDLG, sent|optional },
1312     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1313     { WM_PAINT, sent|optional },
1314     { WM_CTLCOLORBTN, sent },
1315     { WM_ENTERIDLE, sent|parent|optional },
1316     { WM_ENTERIDLE, sent|parent|optional },
1317     { WM_ENTERIDLE, sent|parent|optional },
1318     { WM_ENTERIDLE, sent|parent|optional },
1319     { WM_ENTERIDLE, sent|parent|optional },
1320     { WM_ENTERIDLE, sent|parent|optional },
1321     { WM_ENTERIDLE, sent|parent|optional },
1322     { WM_ENTERIDLE, sent|parent|optional },
1323     { WM_ENTERIDLE, sent|parent|optional },
1324     { WM_ENTERIDLE, sent|parent|optional },
1325     { WM_ENTERIDLE, sent|parent|optional },
1326     { WM_ENTERIDLE, sent|parent|optional },
1327     { WM_ENTERIDLE, sent|parent|optional },
1328     { WM_ENTERIDLE, sent|parent|optional },
1329     { WM_ENTERIDLE, sent|parent|optional },
1330     { WM_ENTERIDLE, sent|parent|optional },
1331     { WM_ENTERIDLE, sent|parent|optional },
1332     { WM_ENTERIDLE, sent|parent|optional },
1333     { WM_ENTERIDLE, sent|parent|optional },
1334     { WM_ENTERIDLE, sent|parent|optional },
1335     { WM_TIMER, sent },
1336     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1337     { WM_ENABLE, sent|parent|wparam, 1 },
1338     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1339     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1340     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1341     { WM_GETTEXT, sent|optional },
1342     { HCBT_ACTIVATE, hook },
1343     { WM_NCACTIVATE, sent|wparam, 0 },
1344     { WM_GETTEXT, sent|optional },
1345     { WM_ACTIVATE, sent|wparam, 0 },
1346     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1347     { WM_WINDOWPOSCHANGING, sent|optional },
1348     { WM_WINDOWPOSCHANGED, sent|optional },
1349     { HCBT_SETFOCUS, hook },
1350     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1351     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1352     { WM_SETFOCUS, sent|parent|defwinproc },
1353     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1354     { HCBT_DESTROYWND, hook },
1355     { 0x0090, sent|optional },
1356     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1357     { WM_DESTROY, sent },
1358     { WM_NCDESTROY, sent },
1359     { 0 }
1360 };
1361 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1362 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1363     /* (inside dialog proc, handling WM_INITDIALOG) */
1364     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1365     { WM_NCCALCSIZE, sent },
1366     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1367     { WM_GETTEXT, sent|defwinproc },
1368     { WM_ACTIVATE, sent|parent|wparam, 0 },
1369     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1370     { WM_WINDOWPOSCHANGING, sent|parent },
1371     { WM_NCACTIVATE, sent|wparam, 1 },
1372     { WM_ACTIVATE, sent|wparam, 1 },
1373     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1374     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1375     /* (setting focus) */
1376     { WM_SHOWWINDOW, sent|wparam, 1 },
1377     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1378     { WM_NCPAINT, sent },
1379     { WM_GETTEXT, sent|defwinproc },
1380     { WM_ERASEBKGND, sent },
1381     { WM_CTLCOLORDLG, sent|defwinproc },
1382     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1383     { WM_PAINT, sent },
1384     /* (bunch of WM_CTLCOLOR* for each control) */
1385     { WM_PAINT, sent|parent },
1386     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1387     { WM_SETCURSOR, sent|parent },
1388     { 0 }
1389 };
1390 /* SetMenu for NonVisible windows with size change*/
1391 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1392     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1393     { WM_NCCALCSIZE, sent|wparam, 1 },
1394     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1395     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1396     { WM_MOVE, sent|defwinproc },
1397     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1398     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1399     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1400     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1401     { WM_GETTEXT, sent|optional },
1402     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1403     { 0 }
1404 };
1405 /* SetMenu for NonVisible windows with no size change */
1406 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1407     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1408     { WM_NCCALCSIZE, sent|wparam, 1 },
1409     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1410     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1411     { 0 }
1412 };
1413 /* SetMenu for Visible windows with size change */
1414 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1415     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1416     { WM_NCCALCSIZE, sent|wparam, 1 },
1417     { 0x0093, sent|defwinproc|optional },
1418     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1419     { WM_NCPAINT, sent }, /* wparam != 1 */
1420     { 0x0093, sent|defwinproc|optional },
1421     { 0x0093, sent|defwinproc|optional },
1422     { 0x0091, sent|defwinproc|optional },
1423     { 0x0092, sent|defwinproc|optional },
1424     { WM_GETTEXT, sent|defwinproc|optional },
1425     { WM_ERASEBKGND, sent|optional },
1426     { WM_ACTIVATE, sent|optional },
1427     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1428     { WM_MOVE, sent|defwinproc },
1429     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1430     { 0x0093, sent|optional },
1431     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1432     { 0x0093, sent|defwinproc|optional },
1433     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1434     { 0x0093, sent|defwinproc|optional },
1435     { 0x0093, sent|defwinproc|optional },
1436     { 0x0091, sent|defwinproc|optional },
1437     { 0x0092, sent|defwinproc|optional },
1438     { WM_ERASEBKGND, sent|optional },
1439     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1440     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1441     { 0 }
1442 };
1443 /* SetMenu for Visible windows with no size change */
1444 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1445     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1446     { WM_NCCALCSIZE, sent|wparam, 1 },
1447     { WM_NCPAINT, sent }, /* wparam != 1 */
1448     { WM_GETTEXT, sent|defwinproc|optional },
1449     { WM_ERASEBKGND, sent|optional },
1450     { WM_ACTIVATE, sent|optional },
1451     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1452     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1453     { 0 }
1454 };
1455 /* DrawMenuBar for a visible window */
1456 static const struct message WmDrawMenuBarSeq[] =
1457 {
1458     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1459     { WM_NCCALCSIZE, sent|wparam, 1 },
1460     { 0x0093, sent|defwinproc|optional },
1461     { WM_NCPAINT, sent }, /* wparam != 1 */
1462     { 0x0093, sent|defwinproc|optional },
1463     { 0x0093, sent|defwinproc|optional },
1464     { 0x0091, sent|defwinproc|optional },
1465     { 0x0092, sent|defwinproc|optional },
1466     { WM_GETTEXT, sent|defwinproc|optional },
1467     { WM_ERASEBKGND, sent|optional },
1468     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1469     { 0x0093, sent|optional },
1470     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1471     { 0 }
1472 };
1473
1474 static const struct message WmSetRedrawFalseSeq[] =
1475 {
1476     { WM_SETREDRAW, sent|wparam, 0 },
1477     { 0 }
1478 };
1479
1480 static const struct message WmSetRedrawTrueSeq[] =
1481 {
1482     { WM_SETREDRAW, sent|wparam, 1 },
1483     { 0 }
1484 };
1485
1486 static const struct message WmEnableWindowSeq_1[] =
1487 {
1488     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1489     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1490     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1491     { 0 }
1492 };
1493
1494 static const struct message WmEnableWindowSeq_2[] =
1495 {
1496     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1497     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1498     { 0 }
1499 };
1500
1501 static const struct message WmGetScrollRangeSeq[] =
1502 {
1503     { SBM_GETRANGE, sent },
1504     { 0 }
1505 };
1506 static const struct message WmGetScrollInfoSeq[] =
1507 {
1508     { SBM_GETSCROLLINFO, sent },
1509     { 0 }
1510 };
1511 static const struct message WmSetScrollRangeSeq[] =
1512 {
1513     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1514        sends SBM_SETSCROLLINFO.
1515      */
1516     { SBM_SETSCROLLINFO, sent },
1517     { 0 }
1518 };
1519 /* SetScrollRange for a window without a non-client area */
1520 static const struct message WmSetScrollRangeHSeq_empty[] =
1521 {
1522     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1523     { 0 }
1524 };
1525 static const struct message WmSetScrollRangeVSeq_empty[] =
1526 {
1527     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1528     { 0 }
1529 };
1530 static const struct message WmSetScrollRangeHVSeq[] =
1531 {
1532     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1533     { WM_NCCALCSIZE, sent|wparam, 1 },
1534     { WM_GETTEXT, sent|defwinproc|optional },
1535     { WM_ERASEBKGND, sent|optional },
1536     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1537     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1538     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1539     { 0 }
1540 };
1541 /* SetScrollRange for a window with a non-client area */
1542 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1543 {
1544     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1545     { WM_NCCALCSIZE, sent|wparam, 1 },
1546     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1547     { WM_NCPAINT, sent|optional },
1548     { WM_STYLECHANGING, sent|defwinproc|optional },
1549     { WM_STYLECHANGED, sent|defwinproc|optional },
1550     { WM_STYLECHANGING, sent|defwinproc|optional },
1551     { WM_STYLECHANGED, sent|defwinproc|optional },
1552     { WM_STYLECHANGING, sent|defwinproc|optional },
1553     { WM_STYLECHANGED, sent|defwinproc|optional },
1554     { WM_STYLECHANGING, sent|defwinproc|optional },
1555     { WM_STYLECHANGED, sent|defwinproc|optional },
1556     { WM_GETTEXT, sent|defwinproc|optional },
1557     { WM_GETTEXT, sent|defwinproc|optional },
1558     { WM_ERASEBKGND, sent|optional },
1559     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1560     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE },
1561     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1562     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1563     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1564     { WM_GETTEXT, sent|optional },
1565     { WM_GETTEXT, sent|optional },
1566     { WM_GETTEXT, sent|optional },
1567     { WM_GETTEXT, sent|optional },
1568     { 0 }
1569 };
1570 /* test if we receive the right sequence of messages */
1571 /* after calling ShowWindow( SW_SHOWNA) */
1572 static const struct message WmSHOWNAChildInvisParInvis[] = {
1573     { WM_SHOWWINDOW, sent|wparam, 1 },
1574     { 0 }
1575 };
1576 static const struct message WmSHOWNAChildVisParInvis[] = {
1577     { WM_SHOWWINDOW, sent|wparam, 1 },
1578     { 0 }
1579 };
1580 static const struct message WmSHOWNAChildVisParVis[] = {
1581     { WM_SHOWWINDOW, sent|wparam, 1 },
1582     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1583     { 0 }
1584 };
1585 static const struct message WmSHOWNAChildInvisParVis[] = {
1586     { WM_SHOWWINDOW, sent|wparam, 1 },
1587     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1588     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1589     { WM_ERASEBKGND, sent|optional },
1590     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1591     { 0 }
1592 };
1593 static const struct message WmSHOWNATopVisible[] = {
1594     { WM_SHOWWINDOW, sent|wparam, 1 },
1595     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1596     { WM_NCPAINT, sent|wparam|optional, 1 },
1597     { WM_GETTEXT, sent|defwinproc|optional },
1598     { WM_ERASEBKGND, sent|optional },
1599     { WM_WINDOWPOSCHANGED, sent|optional },
1600     { 0 }
1601 };
1602 static const struct message WmSHOWNATopInvisible[] = {
1603     { WM_NOTIFYFORMAT, sent|optional },
1604     { WM_QUERYUISTATE, sent|optional },
1605     { WM_WINDOWPOSCHANGING, sent|optional },
1606     { WM_GETMINMAXINFO, sent|optional },
1607     { WM_NCCALCSIZE, sent|optional },
1608     { WM_WINDOWPOSCHANGED, sent|optional },
1609     { WM_SHOWWINDOW, sent|wparam, 1 },
1610     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1611     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1612     { WM_NCPAINT, sent|wparam, 1 },
1613     { WM_GETTEXT, sent|defwinproc|optional },
1614     { WM_ERASEBKGND, sent|optional },
1615     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1616     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1617     { WM_NCPAINT, sent|wparam|optional, 1 },
1618     { WM_ERASEBKGND, sent|optional },
1619     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1620     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1621     { WM_MOVE, sent },
1622     { 0 }
1623 };
1624
1625 static int after_end_dialog, test_def_id;
1626 static int sequence_cnt, sequence_size;
1627 static struct message* sequence;
1628 static int log_all_parent_messages;
1629 static int paint_loop_done;
1630
1631 /* user32 functions */
1632 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
1633 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
1634 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
1635 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
1636 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
1637 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
1638 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
1639 /* kernel32 functions */
1640 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
1641
1642 static void init_procs(void)
1643 {
1644     HMODULE user32 = GetModuleHandleA("user32.dll");
1645     HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
1646
1647 #define GET_PROC(dll, func) \
1648     p ## func = (void*)GetProcAddress(dll, #func); \
1649     if(!p ## func) { \
1650       trace("GetProcAddress(%s) failed\n", #func); \
1651     }
1652
1653     GET_PROC(user32, GetAncestor)
1654     GET_PROC(user32, GetMenuInfo)
1655     GET_PROC(user32, NotifyWinEvent)
1656     GET_PROC(user32, SetMenuInfo)
1657     GET_PROC(user32, SetWinEventHook)
1658     GET_PROC(user32, TrackMouseEvent)
1659     GET_PROC(user32, UnhookWinEvent)
1660
1661     GET_PROC(kernel32, GetCPInfoExA)
1662
1663 #undef GET_PROC
1664 }
1665
1666 static void add_message(const struct message *msg)
1667 {
1668     if (!sequence) 
1669     {
1670         sequence_size = 10;
1671         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1672     }
1673     if (sequence_cnt == sequence_size) 
1674     {
1675         sequence_size *= 2;
1676         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1677     }
1678     assert(sequence);
1679
1680     sequence[sequence_cnt].message = msg->message;
1681     sequence[sequence_cnt].flags = msg->flags;
1682     sequence[sequence_cnt].wParam = msg->wParam;
1683     sequence[sequence_cnt].lParam = msg->lParam;
1684
1685     sequence_cnt++;
1686 }
1687
1688 /* try to make sure pending X events have been processed before continuing */
1689 static void flush_events(void)
1690 {
1691     MSG msg;
1692     int diff = 200;
1693     int min_timeout = 50;
1694     DWORD time = GetTickCount() + diff;
1695
1696     while (diff > 0)
1697     {
1698         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
1699         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1700         diff = time - GetTickCount();
1701         min_timeout = 20;
1702     }
1703 }
1704
1705 static void flush_sequence(void)
1706 {
1707     HeapFree(GetProcessHeap(), 0, sequence);
1708     sequence = 0;
1709     sequence_cnt = sequence_size = 0;
1710 }
1711
1712 #define ok_sequence( exp, contx, todo) \
1713         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1714
1715
1716 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1717         const char *file, int line)
1718 {
1719     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1720     const struct message *actual;
1721     int failcount = 0;
1722     
1723     add_message(&end_of_sequence);
1724
1725     actual = sequence;
1726
1727     while (expected->message && actual->message)
1728     {
1729         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1730
1731         if (expected->message == actual->message)
1732         {
1733             if (expected->flags & wparam)
1734             {
1735                 if (expected->wParam != actual->wParam && todo)
1736                 {
1737                     todo_wine {
1738                         failcount ++;
1739                         ok_( file, line) (FALSE,
1740                             "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1741                             context, expected->message, expected->wParam, actual->wParam);
1742                     }
1743                 }
1744                 else
1745                 ok_( file, line) (expected->wParam == actual->wParam,
1746                      "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
1747                      context, expected->message, expected->wParam, actual->wParam);
1748             }
1749             if (expected->flags & lparam)
1750             {
1751                 if (expected->lParam != actual->lParam && todo)
1752                 {
1753                     todo_wine {
1754                         failcount ++;
1755                         ok_( file, line) (FALSE,
1756                             "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1757                             context, expected->message, expected->lParam, actual->lParam);
1758                     }
1759                 }
1760                 else
1761                  ok_( file, line) (expected->lParam == actual->lParam,
1762                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1763                      context, expected->message, expected->lParam, actual->lParam);
1764             }
1765             if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
1766             {
1767                     todo_wine {
1768                         failcount ++;
1769                         ok_( file, line) (FALSE,
1770                             "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1771                             context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1772                     }
1773             }
1774             else
1775                 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1776                     "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1777                     context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1778             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1779                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1780                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1781             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1782                 "%s: the msg 0x%04x should have been %s\n",
1783                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1784             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1785                 "%s: the msg 0x%04x was expected in %s\n",
1786                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1787             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1788                 "%s: the msg 0x%04x should have been sent by a hook\n",
1789                 context, expected->message);
1790             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1791                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1792                 context, expected->message);
1793             expected++;
1794             actual++;
1795         }
1796         /* silently drop winevent messages if there is no support for them */
1797         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1798             expected++;
1799         else if (todo)
1800         {
1801             failcount++;
1802             todo_wine {
1803                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1804                     context, expected->message, actual->message);
1805             }
1806             flush_sequence();
1807             return;
1808         }
1809         else
1810         {
1811             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1812                 context, expected->message, actual->message);
1813             expected++;
1814             actual++;
1815         }
1816     }
1817
1818     /* skip all optional trailing messages */
1819     while (expected->message && ((expected->flags & optional) ||
1820             ((expected->flags & winevent_hook) && !hEvent_hook)))
1821         expected++;
1822
1823     if (todo)
1824     {
1825         todo_wine {
1826             if (expected->message || actual->message) {
1827                 failcount++;
1828                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1829                     context, expected->message, actual->message);
1830             }
1831         }
1832     }
1833     else
1834     {
1835         if (expected->message || actual->message)
1836             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1837                 context, expected->message, actual->message);
1838     }
1839     if( todo && !failcount) /* succeeded yet marked todo */
1840         todo_wine {
1841             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1842         }
1843
1844     flush_sequence();
1845 }
1846
1847 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
1848
1849 /******************************** MDI test **********************************/
1850
1851 /* CreateWindow for MDI frame window, initially visible */
1852 static const struct message WmCreateMDIframeSeq[] = {
1853     { HCBT_CREATEWND, hook },
1854     { WM_GETMINMAXINFO, sent },
1855     { WM_NCCREATE, sent },
1856     { WM_NCCALCSIZE, sent|wparam, 0 },
1857     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1858     { WM_CREATE, sent },
1859     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1860     { WM_NOTIFYFORMAT, sent|optional },
1861     { WM_QUERYUISTATE, sent|optional },
1862     { WM_WINDOWPOSCHANGING, sent|optional },
1863     { WM_GETMINMAXINFO, sent|optional },
1864     { WM_NCCALCSIZE, sent|optional },
1865     { WM_WINDOWPOSCHANGED, sent|optional },
1866     { WM_SHOWWINDOW, sent|wparam, 1 },
1867     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1868     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1869     { HCBT_ACTIVATE, hook },
1870     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1871     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1872     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
1873     { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
1874     { WM_NCACTIVATE, sent|wparam, 1 },
1875     { WM_GETTEXT, sent|defwinproc|optional },
1876     { WM_ACTIVATE, sent|wparam, 1 },
1877     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
1878     { HCBT_SETFOCUS, hook },
1879     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1880     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1881     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1882     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1883     /* Win9x adds SWP_NOZORDER below */
1884     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1885     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1886     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1887     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1888     { WM_MOVE, sent },
1889     { 0 }
1890 };
1891 /* DestroyWindow for MDI frame window, initially visible */
1892 static const struct message WmDestroyMDIframeSeq[] = {
1893     { HCBT_DESTROYWND, hook },
1894     { 0x0090, sent|optional },
1895     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1896     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1897     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1898     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1899     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
1900     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1901     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1902     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1903     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1904     { WM_DESTROY, sent },
1905     { WM_NCDESTROY, sent },
1906     { 0 }
1907 };
1908 /* CreateWindow for MDI client window, initially visible */
1909 static const struct message WmCreateMDIclientSeq[] = {
1910     { HCBT_CREATEWND, hook },
1911     { WM_NCCREATE, sent },
1912     { WM_NCCALCSIZE, sent|wparam, 0 },
1913     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1914     { WM_CREATE, sent },
1915     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
1916     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1917     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1918     { WM_MOVE, sent },
1919     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1920     { WM_SHOWWINDOW, sent|wparam, 1 },
1921     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1922     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1923     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1924     { 0 }
1925 };
1926 /* ShowWindow(SW_SHOW) for MDI client window */
1927 static const struct message WmShowMDIclientSeq[] = {
1928     { WM_SHOWWINDOW, sent|wparam, 1 },
1929     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1930     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1931     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1932     { 0 }
1933 };
1934 /* ShowWindow(SW_HIDE) for MDI client window */
1935 static const struct message WmHideMDIclientSeq[] = {
1936     { WM_SHOWWINDOW, sent|wparam, 0 },
1937     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1938     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
1939     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
1940     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1941     { 0 }
1942 };
1943 /* DestroyWindow for MDI client window, initially visible */
1944 static const struct message WmDestroyMDIclientSeq[] = {
1945     { HCBT_DESTROYWND, hook },
1946     { 0x0090, sent|optional },
1947     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1948     { WM_SHOWWINDOW, sent|wparam, 0 },
1949     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1950     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1951     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1952     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1953     { WM_DESTROY, sent },
1954     { WM_NCDESTROY, sent },
1955     { 0 }
1956 };
1957 /* CreateWindow for MDI child window, initially visible */
1958 static const struct message WmCreateMDIchildVisibleSeq[] = {
1959     { HCBT_CREATEWND, hook },
1960     { WM_NCCREATE, sent }, 
1961     { WM_NCCALCSIZE, sent|wparam, 0 },
1962     { WM_CREATE, sent },
1963     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1964     { WM_SIZE, sent|wparam, SIZE_RESTORED },
1965     { WM_MOVE, sent },
1966     /* Win2k sends wparam set to
1967      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1968      * while Win9x doesn't bother to set child window id according to
1969      * CLIENTCREATESTRUCT.idFirstChild
1970      */
1971     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1972     { WM_SHOWWINDOW, sent|wparam, 1 },
1973     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1974     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1975     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1976     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1977     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1978     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1979     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1980
1981     /* Win9x: message sequence terminates here. */
1982
1983     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1984     { HCBT_SETFOCUS, hook }, /* in MDI client */
1985     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1986     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
1987     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1988     { WM_SETFOCUS, sent }, /* in MDI client */
1989     { HCBT_SETFOCUS, hook },
1990     { WM_KILLFOCUS, sent }, /* in MDI client */
1991     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1992     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1993     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1994     { WM_SETFOCUS, sent|defwinproc },
1995     { WM_MDIACTIVATE, sent|defwinproc },
1996     { 0 }
1997 };
1998 /* CreateWindow for MDI child window with invisible parent */
1999 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2000     { HCBT_CREATEWND, hook },
2001     { WM_GETMINMAXINFO, sent },
2002     { WM_NCCREATE, sent }, 
2003     { WM_NCCALCSIZE, sent|wparam, 0 },
2004     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2005     { WM_CREATE, sent },
2006     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2007     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2008     { WM_MOVE, sent },
2009     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2010     { WM_SHOWWINDOW, sent|wparam, 1 },
2011     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2012     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2013     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2014     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2015
2016     /* Win9x: message sequence terminates here. */
2017
2018     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2019     { HCBT_SETFOCUS, hook }, /* in MDI client */
2020     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2021     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2022     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2023     { WM_SETFOCUS, sent }, /* in MDI client */
2024     { HCBT_SETFOCUS, hook },
2025     { WM_KILLFOCUS, sent }, /* in MDI client */
2026     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2027     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2028     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2029     { WM_SETFOCUS, sent|defwinproc },
2030     { WM_MDIACTIVATE, sent|defwinproc },
2031     { 0 }
2032 };
2033 /* DestroyWindow for MDI child window, initially visible */
2034 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2035     { HCBT_DESTROYWND, hook },
2036     /* Win2k sends wparam set to
2037      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2038      * while Win9x doesn't bother to set child window id according to
2039      * CLIENTCREATESTRUCT.idFirstChild
2040      */
2041     { 0x0090, sent|optional },
2042     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2043     { WM_SHOWWINDOW, sent|wparam, 0 },
2044     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2045     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2046     { WM_ERASEBKGND, sent|parent|optional },
2047     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2048
2049     /* { WM_DESTROY, sent }
2050      * Win9x: message sequence terminates here.
2051      */
2052
2053     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2054     { WM_KILLFOCUS, sent },
2055     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2056     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2057     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2058     { WM_SETFOCUS, sent }, /* in MDI client */
2059
2060     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2061     { WM_KILLFOCUS, sent }, /* in MDI client */
2062     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2063     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2064     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2065     { WM_SETFOCUS, sent }, /* in MDI client */
2066
2067     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2068
2069     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2070     { WM_KILLFOCUS, sent },
2071     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2072     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2073     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2074     { WM_SETFOCUS, sent }, /* in MDI client */
2075
2076     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2077     { WM_KILLFOCUS, sent }, /* in MDI client */
2078     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2079     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2080     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2081     { WM_SETFOCUS, sent }, /* in MDI client */
2082
2083     { WM_DESTROY, sent },
2084
2085     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2086     { WM_KILLFOCUS, sent },
2087     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2088     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2089     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2090     { WM_SETFOCUS, sent }, /* in MDI client */
2091
2092     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2093     { WM_KILLFOCUS, sent }, /* in MDI client */
2094     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2095     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2096     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2097     { WM_SETFOCUS, sent }, /* in MDI client */
2098
2099     { WM_NCDESTROY, sent },
2100     { 0 }
2101 };
2102 /* CreateWindow for MDI child window, initially invisible */
2103 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2104     { HCBT_CREATEWND, hook },
2105     { WM_NCCREATE, sent }, 
2106     { WM_NCCALCSIZE, sent|wparam, 0 },
2107     { WM_CREATE, sent },
2108     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2109     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2110     { WM_MOVE, sent },
2111     /* Win2k sends wparam set to
2112      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2113      * while Win9x doesn't bother to set child window id according to
2114      * CLIENTCREATESTRUCT.idFirstChild
2115      */
2116     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2117     { 0 }
2118 };
2119 /* DestroyWindow for MDI child window, initially invisible */
2120 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2121     { HCBT_DESTROYWND, hook },
2122     /* Win2k sends wparam set to
2123      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2124      * while Win9x doesn't bother to set child window id according to
2125      * CLIENTCREATESTRUCT.idFirstChild
2126      */
2127     { 0x0090, sent|optional },
2128     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2129     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2130     { WM_DESTROY, sent },
2131     { WM_NCDESTROY, sent },
2132     /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2133     { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2134     { 0 }
2135 };
2136 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2137 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2138     { HCBT_CREATEWND, hook },
2139     { WM_NCCREATE, sent }, 
2140     { WM_NCCALCSIZE, sent|wparam, 0 },
2141     { WM_CREATE, sent },
2142     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2143     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2144     { WM_MOVE, sent },
2145     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2146     { WM_GETMINMAXINFO, sent },
2147     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED  },
2148     { WM_NCCALCSIZE, sent|wparam, 1 },
2149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2150     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2151      /* in MDI frame */
2152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2153     { WM_NCCALCSIZE, sent|wparam, 1 },
2154     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2155     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2156     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2157     /* Win2k sends wparam set to
2158      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2159      * while Win9x doesn't bother to set child window id according to
2160      * CLIENTCREATESTRUCT.idFirstChild
2161      */
2162     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2163     { WM_SHOWWINDOW, sent|wparam, 1 },
2164     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2165     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2166     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2167     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2168     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2169     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2170     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2171
2172     /* Win9x: message sequence terminates here. */
2173
2174     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2175     { HCBT_SETFOCUS, hook }, /* in MDI client */
2176     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2177     { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2178     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2179     { WM_SETFOCUS, sent }, /* in MDI client */
2180     { HCBT_SETFOCUS, hook },
2181     { WM_KILLFOCUS, sent }, /* in MDI client */
2182     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2183     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2184     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2185     { WM_SETFOCUS, sent|defwinproc },
2186     { WM_MDIACTIVATE, sent|defwinproc },
2187      /* in MDI frame */
2188     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2189     { WM_NCCALCSIZE, sent|wparam, 1 },
2190     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2191     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2192     { 0 }
2193 };
2194 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2195 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2196     /* restore the 1st MDI child */
2197     { WM_SETREDRAW, sent|wparam, 0 },
2198     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2199     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2200     { WM_NCCALCSIZE, sent|wparam, 1 },
2201     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2202     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2203     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2204      /* in MDI frame */
2205     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2206     { WM_NCCALCSIZE, sent|wparam, 1 },
2207     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2208     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2209     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2210     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2211     /* create the 2nd MDI child */
2212     { HCBT_CREATEWND, hook },
2213     { WM_NCCREATE, sent }, 
2214     { WM_NCCALCSIZE, sent|wparam, 0 },
2215     { WM_CREATE, sent },
2216     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2217     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2218     { WM_MOVE, sent },
2219     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2220     { WM_GETMINMAXINFO, sent },
2221     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2222     { WM_NCCALCSIZE, sent|wparam, 1 },
2223     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2224     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2225     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2226      /* in MDI frame */
2227     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2228     { WM_NCCALCSIZE, sent|wparam, 1 },
2229     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2230     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2231     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2232     /* Win2k sends wparam set to
2233      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2234      * while Win9x doesn't bother to set child window id according to
2235      * CLIENTCREATESTRUCT.idFirstChild
2236      */
2237     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2238     { WM_SHOWWINDOW, sent|wparam, 1 },
2239     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2240     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2241     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2242     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2243     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2244     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2245
2246     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2247     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2248
2249     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2250
2251     /* Win9x: message sequence terminates here. */
2252
2253     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2254     { HCBT_SETFOCUS, hook },
2255     { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
2256     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
2257     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2258     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2259     { WM_SETFOCUS, sent }, /* in MDI client */
2260     { HCBT_SETFOCUS, hook },
2261     { WM_KILLFOCUS, sent }, /* in MDI client */
2262     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2263     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2264     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2265     { WM_SETFOCUS, sent|defwinproc },
2266
2267     { WM_MDIACTIVATE, sent|defwinproc },
2268      /* in MDI frame */
2269     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2270     { WM_NCCALCSIZE, sent|wparam, 1 },
2271     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2272     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2273     { 0 }
2274 };
2275 /* WM_MDICREATE MDI child window, initially visible and maximized */
2276 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
2277     { WM_MDICREATE, sent },
2278     { HCBT_CREATEWND, hook },
2279     { WM_NCCREATE, sent }, 
2280     { WM_NCCALCSIZE, sent|wparam, 0 },
2281     { WM_CREATE, sent },
2282     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2283     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2284     { WM_MOVE, sent },
2285     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2286     { WM_GETMINMAXINFO, sent },
2287     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2288     { WM_NCCALCSIZE, sent|wparam, 1 },
2289     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2290     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2291
2292      /* in MDI frame */
2293     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2294     { WM_NCCALCSIZE, sent|wparam, 1 },
2295     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2296     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2297     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2298
2299     /* Win2k sends wparam set to
2300      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2301      * while Win9x doesn't bother to set child window id according to
2302      * CLIENTCREATESTRUCT.idFirstChild
2303      */
2304     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2305     { WM_SHOWWINDOW, sent|wparam, 1 },
2306     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2307
2308     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2309
2310     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2311     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2312     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2313
2314     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2315     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2316
2317     /* Win9x: message sequence terminates here. */
2318
2319     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2320     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2321     { HCBT_SETFOCUS, hook }, /* in MDI client */
2322     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2323     { WM_IME_NOTIFY, sent|wparam|optional, 2 },
2324     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
2325     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2326     { HCBT_SETFOCUS, hook|optional },
2327     { WM_KILLFOCUS, sent }, /* in MDI client */
2328     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2329     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2330     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2331     { WM_SETFOCUS, sent|defwinproc },
2332
2333     { WM_MDIACTIVATE, sent|defwinproc },
2334
2335      /* in MDI child */
2336     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2337     { WM_NCCALCSIZE, sent|wparam, 1 },
2338     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2339     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2340
2341      /* in MDI frame */
2342     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2343     { WM_NCCALCSIZE, sent|wparam, 1 },
2344     { 0x0093, sent|defwinproc|optional },
2345     { 0x0093, sent|defwinproc|optional },
2346     { 0x0093, sent|defwinproc|optional },
2347     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2348     { WM_MOVE, sent|defwinproc },
2349     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2350
2351      /* in MDI client */
2352     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2353     { WM_NCCALCSIZE, sent|wparam, 1 },
2354     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2355     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2356
2357      /* in MDI child */
2358     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2359     { WM_NCCALCSIZE, sent|wparam, 1 },
2360     { 0x0093, sent|optional },
2361     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2362     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2363
2364     { 0x0093, sent|optional },
2365     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2366     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2367     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
2368     { 0x0093, sent|defwinproc|optional },
2369     { 0x0093, sent|defwinproc|optional },
2370     { 0x0093, sent|defwinproc|optional },
2371     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2372     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2373
2374     { 0 }
2375 };
2376 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
2377 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
2378     { HCBT_CREATEWND, hook },
2379     { WM_GETMINMAXINFO, sent },
2380     { WM_NCCREATE, sent }, 
2381     { WM_NCCALCSIZE, sent|wparam, 0 },
2382     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2383     { WM_CREATE, sent },
2384     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2385     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2386     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE }, /* MDI frame */
2387     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
2388     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* MDI frame */
2389     { WM_MOVE, sent },
2390     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2391     { WM_GETMINMAXINFO, sent },
2392     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2393     { WM_GETMINMAXINFO, sent|defwinproc },
2394     { WM_NCCALCSIZE, sent|wparam, 1 },
2395     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2396     { WM_MOVE, sent|defwinproc },
2397     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2398      /* in MDI frame */
2399     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2400     { WM_NCCALCSIZE, sent|wparam, 1 },
2401     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2402     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2403     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
2404     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2405     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2406     /* Win2k sends wparam set to
2407      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2408      * while Win9x doesn't bother to set child window id according to
2409      * CLIENTCREATESTRUCT.idFirstChild
2410      */
2411     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2412     { 0 }
2413 };
2414 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
2415 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
2416     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
2417     { HCBT_SYSCOMMAND, hook },
2418     { WM_CLOSE, sent|defwinproc },
2419     { WM_MDIDESTROY, sent }, /* in MDI client */
2420
2421     /* bring the 1st MDI child to top */
2422     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
2423     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
2424
2425     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2426
2427     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
2428     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
2429     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
2430
2431     /* maximize the 1st MDI child */
2432     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2433     { WM_GETMINMAXINFO, sent|defwinproc },
2434     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
2435     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2436     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
2437     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2438     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2439
2440     /* restore the 2nd MDI child */
2441     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
2442     { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
2443     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2444     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
2445
2446     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2447
2448     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2449     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2450
2451     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2452
2453     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
2454      /* in MDI frame */
2455     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2456     { WM_NCCALCSIZE, sent|wparam, 1 },
2457     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2458     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2459     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2460
2461     /* bring the 1st MDI child to top */
2462     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2463     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2464     { HCBT_SETFOCUS, hook },
2465     { WM_KILLFOCUS, sent|defwinproc },
2466     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
2467     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2468     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2469     { WM_SETFOCUS, sent }, /* in MDI client */
2470     { HCBT_SETFOCUS, hook },
2471     { WM_KILLFOCUS, sent }, /* in MDI client */
2472     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2473     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2474     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2475     { WM_SETFOCUS, sent|defwinproc },
2476     { WM_MDIACTIVATE, sent|defwinproc },
2477     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2478
2479     /* apparently ShowWindow(SW_SHOW) on an MDI client */
2480     { WM_SHOWWINDOW, sent|wparam, 1 },
2481     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2482     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2484     { WM_MDIREFRESHMENU, sent },
2485
2486     { HCBT_DESTROYWND, hook },
2487     /* Win2k sends wparam set to
2488      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2489      * while Win9x doesn't bother to set child window id according to
2490      * CLIENTCREATESTRUCT.idFirstChild
2491      */
2492     { 0x0090, sent|defwinproc|optional },
2493     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2494     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
2495     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2496     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2497     { WM_ERASEBKGND, sent|parent|optional },
2498     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2499
2500     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2501     { WM_DESTROY, sent|defwinproc },
2502     { WM_NCDESTROY, sent|defwinproc },
2503     { 0 }
2504 };
2505 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
2506 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
2507     { WM_MDIDESTROY, sent }, /* in MDI client */
2508     { WM_SHOWWINDOW, sent|wparam, 0 },
2509     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2510     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2511     { WM_ERASEBKGND, sent|parent|optional },
2512     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2513
2514     { HCBT_SETFOCUS, hook },
2515     { WM_KILLFOCUS, sent },
2516     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2517     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2518     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2519     { WM_SETFOCUS, sent }, /* in MDI client */
2520     { HCBT_SETFOCUS, hook },
2521     { WM_KILLFOCUS, sent }, /* in MDI client */
2522     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2523     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2524     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2525     { WM_SETFOCUS, sent },
2526
2527      /* in MDI child */
2528     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2529     { WM_NCCALCSIZE, sent|wparam, 1 },
2530     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2531     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2532
2533      /* in MDI frame */
2534     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2535     { WM_NCCALCSIZE, sent|wparam, 1 },
2536     { 0x0093, sent|defwinproc|optional },
2537     { 0x0093, sent|defwinproc|optional },
2538     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2539     { WM_MOVE, sent|defwinproc },
2540     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2541
2542      /* in MDI client */
2543     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2544     { WM_NCCALCSIZE, sent|wparam, 1 },
2545     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2546     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2547
2548      /* in MDI child */
2549     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2550     { WM_NCCALCSIZE, sent|wparam, 1 },
2551     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2552     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2553
2554      /* in MDI child */
2555     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2556     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2557     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2558     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2559
2560      /* in MDI frame */
2561     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2562     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2563     { 0x0093, sent|defwinproc|optional },
2564     { 0x0093, sent|defwinproc|optional },
2565     { 0x0093, sent|defwinproc|optional },
2566     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2567     { WM_MOVE, sent|defwinproc },
2568     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2569
2570      /* in MDI client */
2571     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2572     { WM_NCCALCSIZE, sent|wparam, 1 },
2573     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2574     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2575
2576      /* in MDI child */
2577     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2578     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2579     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2580     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2581     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2582     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2583
2584     { 0x0093, sent|defwinproc|optional },
2585     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2586     { 0x0093, sent|defwinproc|optional },
2587     { 0x0093, sent|defwinproc|optional },
2588     { 0x0093, sent|defwinproc|optional },
2589     { 0x0093, sent|optional },
2590
2591     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2592     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2593     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2594     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2595     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2596
2597      /* in MDI frame */
2598     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2599     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2600     { 0x0093, sent|defwinproc|optional },
2601     { 0x0093, sent|defwinproc|optional },
2602     { 0x0093, sent|defwinproc|optional },
2603     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2604     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2605     { 0x0093, sent|optional },
2606
2607     { WM_NCACTIVATE, sent|wparam, 0 },
2608     { WM_MDIACTIVATE, sent },
2609
2610     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2611     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
2612     { WM_NCCALCSIZE, sent|wparam, 1 },
2613
2614     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2615
2616     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2618     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2619
2620      /* in MDI child */
2621     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2622     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2623     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2624     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2625
2626      /* in MDI frame */
2627     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2628     { WM_NCCALCSIZE, sent|wparam, 1 },
2629     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2630     { WM_MOVE, sent|defwinproc },
2631     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2632
2633      /* in MDI client */
2634     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2635     { WM_NCCALCSIZE, sent|wparam, 1 },
2636     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
2637     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2638     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2639     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2640     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2641     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2642     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2643
2644     { HCBT_SETFOCUS, hook },
2645     { WM_KILLFOCUS, sent },
2646     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2647     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2648     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2649     { WM_SETFOCUS, sent }, /* in MDI client */
2650
2651     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2652
2653     { HCBT_DESTROYWND, hook },
2654     /* Win2k sends wparam set to
2655      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2656      * while Win9x doesn't bother to set child window id according to
2657      * CLIENTCREATESTRUCT.idFirstChild
2658      */
2659     { 0x0090, sent|optional },
2660     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2661
2662     { WM_SHOWWINDOW, sent|wparam, 0 },
2663     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2664     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2665     { WM_ERASEBKGND, sent|parent|optional },
2666     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2667
2668     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2669     { WM_DESTROY, sent },
2670     { WM_NCDESTROY, sent },
2671     { 0 }
2672 };
2673 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2674 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2675     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2676     { WM_GETMINMAXINFO, sent },
2677     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
2678     { WM_NCCALCSIZE, sent|wparam, 1 },
2679     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2680     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2681
2682     { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2683     { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
2684     { HCBT_SETFOCUS, hook|optional },
2685     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2686     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2687     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2688     { HCBT_SETFOCUS, hook|optional },
2689     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2690     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2691     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2692     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2693     { WM_SETFOCUS, sent|optional|defwinproc },
2694     { WM_MDIACTIVATE, sent|optional|defwinproc },
2695     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2696     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2697      /* in MDI frame */
2698     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2699     { WM_NCCALCSIZE, sent|wparam, 1 },
2700     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2701     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2702     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2703     { 0 }
2704 };
2705 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
2706 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
2707     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2708     { WM_GETMINMAXINFO, sent },
2709     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
2710     { WM_GETMINMAXINFO, sent|defwinproc },
2711     { WM_NCCALCSIZE, sent|wparam, 1 },
2712     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2713     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2714
2715     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2716     { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2717     { HCBT_SETFOCUS, hook|optional },
2718     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2719     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2720     { WM_SETFOCUS, sent|optional }, /* in MDI client */
2721     { HCBT_SETFOCUS, hook|optional },
2722     { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2723     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2724     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2725     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2726     { WM_SETFOCUS, sent|defwinproc|optional },
2727     { WM_MDIACTIVATE, sent|defwinproc|optional },
2728     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2729     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2730     { 0 }
2731 };
2732 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
2733 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
2734     { WM_MDIMAXIMIZE, sent }, /* in MDI client */
2735     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2736     { WM_GETMINMAXINFO, sent },
2737     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2738     { WM_GETMINMAXINFO, sent|defwinproc },
2739     { WM_NCCALCSIZE, sent|wparam, 1 },
2740     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
2741     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2742     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
2743     { WM_MOVE, sent|defwinproc },
2744     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2745
2746     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2747     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2748     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2749     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2750     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2751     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2752      /* in MDI frame */
2753     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2754     { WM_NCCALCSIZE, sent|wparam, 1 },
2755     { 0x0093, sent|defwinproc|optional },
2756     { 0x0094, sent|defwinproc|optional },
2757     { 0x0094, sent|defwinproc|optional },
2758     { 0x0094, sent|defwinproc|optional },
2759     { 0x0094, sent|defwinproc|optional },
2760     { 0x0093, sent|defwinproc|optional },
2761     { 0x0093, sent|defwinproc|optional },
2762     { 0x0091, sent|defwinproc|optional },
2763     { 0x0092, sent|defwinproc|optional },
2764     { 0x0092, sent|defwinproc|optional },
2765     { 0x0092, sent|defwinproc|optional },
2766     { 0x0092, sent|defwinproc|optional },
2767     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2768     { WM_MOVE, sent|defwinproc },
2769     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2770     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
2771      /* in MDI client */
2772     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
2773     { WM_NCCALCSIZE, sent|wparam, 1 },
2774     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2775     { WM_SIZE, sent|wparam, SIZE_RESTORED },
2776      /* in MDI child */
2777     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
2778     { WM_GETMINMAXINFO, sent|defwinproc },
2779     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2780     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2781     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2782     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
2783     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
2784     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2785     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2786     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
2787      /* in MDI frame */
2788     { 0x0093, sent|optional },
2789     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
2790     { 0x0093, sent|defwinproc|optional },
2791     { 0x0093, sent|defwinproc|optional },
2792     { 0x0093, sent|defwinproc|optional },
2793     { 0x0091, sent|defwinproc|optional },
2794     { 0x0092, sent|defwinproc|optional },
2795     { 0x0092, sent|defwinproc|optional },
2796     { 0x0092, sent|defwinproc|optional },
2797     { 0x0092, sent|defwinproc|optional },
2798     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2799     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
2800     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
2801     { 0 }
2802 };
2803 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2804 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2805     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2806     { WM_GETMINMAXINFO, sent },
2807     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2808     { WM_NCCALCSIZE, sent|wparam, 1 },
2809     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2810     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2811     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2812      /* in MDI frame */
2813     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2814     { WM_NCCALCSIZE, sent|wparam, 1 },
2815     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2816     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2817     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2818     { 0 }
2819 };
2820 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
2821 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2822     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2823     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2824     { WM_NCCALCSIZE, sent|wparam, 1 },
2825     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2826     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2827     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2828      /* in MDI frame */
2829     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2830     { WM_NCCALCSIZE, sent|wparam, 1 },
2831     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2832     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2833     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2834     { 0 }
2835 };
2836 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
2837 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
2838     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2839     { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
2840     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
2841     { WM_NCCALCSIZE, sent|wparam, 1 },
2842     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2843     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2844     { WM_MOVE, sent|defwinproc },
2845     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2846     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2847     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2848     { HCBT_SETFOCUS, hook },
2849     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2850     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2851     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2852     { WM_SETFOCUS, sent },
2853     { 0 }
2854 };
2855 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
2856 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
2857     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
2858     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
2859     { WM_NCCALCSIZE, sent|wparam, 1 },
2860     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED },
2861     { WM_MOVE, sent|defwinproc },
2862     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
2863     { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
2864     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2865     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2866     /* FIXME: Wine creates an icon/title window while Windows doesn't */
2867     { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
2868     { 0 }
2869 };
2870 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2871 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2872     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
2873     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
2874     { WM_NCCALCSIZE, sent|wparam, 1 },
2875     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2876     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2877     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2878     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2879      /* in MDI frame */
2880     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2881     { WM_NCCALCSIZE, sent|wparam, 1 },
2882     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2883     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2884     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2885     { 0 }
2886 };
2887
2888 static HWND mdi_client;
2889 static WNDPROC old_mdi_client_proc;
2890
2891 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2892 {
2893     struct message msg;
2894
2895     /* do not log painting messages */
2896     if (message != WM_PAINT &&
2897         message != WM_NCPAINT &&
2898         message != WM_SYNCPAINT &&
2899         message != WM_ERASEBKGND &&
2900         message != WM_NCHITTEST &&
2901         message != WM_GETTEXT &&
2902         message != WM_MDIGETACTIVE &&
2903         message != WM_GETICON &&
2904         message != WM_DEVICECHANGE)
2905     {
2906         trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2907
2908         switch (message)
2909         {
2910             case WM_WINDOWPOSCHANGING:
2911             case WM_WINDOWPOSCHANGED:
2912             {
2913                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2914
2915                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2916                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2917                       winpos->hwnd, winpos->hwndInsertAfter,
2918                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2919                 dump_winpos_flags(winpos->flags);
2920
2921                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2922                  * in the high word for internal purposes
2923                  */
2924                 wParam = winpos->flags & 0xffff;
2925                 /* We are not interested in the flags that don't match under XP and Win9x */
2926                 wParam &= ~(SWP_NOZORDER);
2927                 break;
2928             }
2929         }
2930
2931         msg.message = message;
2932         msg.flags = sent|wparam|lparam;
2933         msg.wParam = wParam;
2934         msg.lParam = lParam;
2935         add_message(&msg);
2936     }
2937
2938     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2939 }
2940
2941 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2942 {
2943     static long defwndproc_counter = 0;
2944     LRESULT ret;
2945     struct message msg;
2946
2947     /* do not log painting messages */
2948     if (message != WM_PAINT &&
2949         message != WM_NCPAINT &&
2950         message != WM_SYNCPAINT &&
2951         message != WM_ERASEBKGND &&
2952         message != WM_NCHITTEST &&
2953         message != WM_GETTEXT &&
2954         message != WM_GETICON &&
2955         message != WM_DEVICECHANGE)
2956     {
2957         trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
2958
2959         switch (message)
2960         {
2961             case WM_WINDOWPOSCHANGING:
2962             case WM_WINDOWPOSCHANGED:
2963             {
2964                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2965
2966                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2967                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
2968                       winpos->hwnd, winpos->hwndInsertAfter,
2969                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2970                 dump_winpos_flags(winpos->flags);
2971
2972                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2973                  * in the high word for internal purposes
2974                  */
2975                 wParam = winpos->flags & 0xffff;
2976                 /* We are not interested in the flags that don't match under XP and Win9x */
2977                 wParam &= ~(SWP_NOZORDER);
2978                 break;
2979             }
2980
2981             case WM_MDIACTIVATE:
2982             {
2983                 HWND active, client = GetParent(hwnd);
2984
2985                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2986
2987                 if (hwnd == (HWND)lParam) /* if we are being activated */
2988                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2989                 else
2990                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2991                 break;
2992             }
2993         }
2994
2995         msg.message = message;
2996         msg.flags = sent|wparam|lparam;
2997         if (defwndproc_counter) msg.flags |= defwinproc;
2998         msg.wParam = wParam;
2999         msg.lParam = lParam;
3000         add_message(&msg);
3001     }
3002
3003     defwndproc_counter++;
3004     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3005     defwndproc_counter--;
3006
3007     return ret;
3008 }
3009
3010 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3011 {
3012     static long defwndproc_counter = 0;
3013     LRESULT ret;
3014     struct message msg;
3015
3016     /* do not log painting messages */
3017     if (message != WM_PAINT &&
3018         message != WM_NCPAINT &&
3019         message != WM_SYNCPAINT &&
3020         message != WM_ERASEBKGND &&
3021         message != WM_NCHITTEST &&
3022         message != WM_GETTEXT &&
3023         message != WM_GETICON &&
3024         message != WM_DEVICECHANGE &&
3025         message < 0xc000)
3026     {
3027         trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3028
3029         switch (message)
3030         {
3031             case WM_WINDOWPOSCHANGING:
3032             case WM_WINDOWPOSCHANGED:
3033             {
3034                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3035
3036                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3037                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
3038                       winpos->hwnd, winpos->hwndInsertAfter,
3039                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3040                 dump_winpos_flags(winpos->flags);
3041
3042                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
3043                  * in the high word for internal purposes
3044                  */
3045                 wParam = winpos->flags & 0xffff;
3046                 /* We are not interested in the flags that don't match under XP and Win9x */
3047                 wParam &= ~(SWP_NOZORDER);
3048                 break;
3049             }
3050         }
3051
3052         msg.message = message;
3053         msg.flags = sent|wparam|lparam;
3054         if (defwndproc_counter) msg.flags |= defwinproc;
3055         msg.wParam = wParam;
3056         msg.lParam = lParam;
3057         add_message(&msg);
3058     }
3059
3060     defwndproc_counter++;
3061     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3062     defwndproc_counter--;
3063
3064     return ret;
3065 }
3066
3067 static BOOL mdi_RegisterWindowClasses(void)
3068 {
3069     WNDCLASSA cls;
3070
3071     cls.style = 0;
3072     cls.lpfnWndProc = mdi_frame_wnd_proc;
3073     cls.cbClsExtra = 0;
3074     cls.cbWndExtra = 0;
3075     cls.hInstance = GetModuleHandleA(0);
3076     cls.hIcon = 0;
3077     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
3078     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3079     cls.lpszMenuName = NULL;
3080     cls.lpszClassName = "MDI_frame_class";
3081     if (!RegisterClassA(&cls)) return FALSE;
3082
3083     cls.lpfnWndProc = mdi_child_wnd_proc;
3084     cls.lpszClassName = "MDI_child_class";
3085     if (!RegisterClassA(&cls)) return FALSE;
3086
3087     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3088     old_mdi_client_proc = cls.lpfnWndProc;
3089     cls.hInstance = GetModuleHandleA(0);
3090     cls.lpfnWndProc = mdi_client_hook_proc;
3091     cls.lpszClassName = "MDI_client_class";
3092     if (!RegisterClassA(&cls)) assert(0);
3093
3094     return TRUE;
3095 }
3096
3097 static void test_mdi_messages(void)
3098 {
3099     MDICREATESTRUCTA mdi_cs;
3100     CLIENTCREATESTRUCT client_cs;
3101     HWND mdi_frame, mdi_child, mdi_child2, active_child;
3102     BOOL zoomed;
3103     HMENU hMenu = CreateMenu();
3104
3105     assert(mdi_RegisterWindowClasses());
3106
3107     flush_sequence();
3108
3109     trace("creating MDI frame window\n");
3110     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3111                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3112                                 WS_MAXIMIZEBOX | WS_VISIBLE,
3113                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3114                                 GetDesktopWindow(), hMenu,
3115                                 GetModuleHandleA(0), NULL);
3116     assert(mdi_frame);
3117     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3118
3119     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3120     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3121
3122     trace("creating MDI client window\n");
3123     client_cs.hWindowMenu = 0;
3124     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3125     mdi_client = CreateWindowExA(0, "MDI_client_class",
3126                                  NULL,
3127                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3128                                  0, 0, 0, 0,
3129                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3130     assert(mdi_client);
3131     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3132
3133     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3134     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3135
3136     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3137     ok(!active_child, "wrong active MDI child %p\n", active_child);
3138     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3139
3140     SetFocus(0);
3141     flush_sequence();
3142
3143     trace("creating invisible MDI child window\n");
3144     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3145                                 WS_CHILD,
3146                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3147                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3148     assert(mdi_child);
3149
3150     flush_sequence();
3151     ShowWindow(mdi_child, SW_SHOWNORMAL);
3152     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3153
3154     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3155     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3156
3157     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3158     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3159
3160     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3161     ok(!active_child, "wrong active MDI child %p\n", active_child);
3162     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3163
3164     ShowWindow(mdi_child, SW_HIDE);
3165     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3166     flush_sequence();
3167
3168     ShowWindow(mdi_child, SW_SHOW);
3169     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3170
3171     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3172     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3173
3174     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3175     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3176
3177     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3178     ok(!active_child, "wrong active MDI child %p\n", active_child);
3179     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3180
3181     DestroyWindow(mdi_child);
3182     flush_sequence();
3183
3184     trace("creating visible MDI child window\n");
3185     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3186                                 WS_CHILD | WS_VISIBLE,
3187                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3188                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3189     assert(mdi_child);
3190     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3191
3192     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3193     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3194
3195     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3196     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3197
3198     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3199     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3200     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3201     flush_sequence();
3202
3203     DestroyWindow(mdi_child);
3204     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3205
3206     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3207     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3208
3209     /* Win2k: MDI client still returns a just destroyed child as active
3210      * Win9x: MDI client returns 0
3211      */
3212     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3213     ok(active_child == mdi_child || /* win2k */
3214        !active_child, /* win9x */
3215        "wrong active MDI child %p\n", active_child);
3216     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3217
3218     flush_sequence();
3219
3220     trace("creating invisible MDI child window\n");
3221     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3222                                 WS_CHILD,
3223                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3224                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3225     assert(mdi_child2);
3226     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3227
3228     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3229     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3230
3231     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3232     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3233
3234     /* Win2k: MDI client still returns a just destroyed child as active
3235      * Win9x: MDI client returns mdi_child2
3236      */
3237     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3238     ok(active_child == mdi_child || /* win2k */
3239        active_child == mdi_child2, /* win9x */
3240        "wrong active MDI child %p\n", active_child);
3241     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3242     flush_sequence();
3243
3244     ShowWindow(mdi_child2, SW_MAXIMIZE);
3245     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3246
3247     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3248     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3249
3250     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3251     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3252     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3253     flush_sequence();
3254
3255     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3256     ok(GetFocus() == mdi_child2 || /* win2k */
3257        GetFocus() == 0, /* win9x */
3258        "wrong focus window %p\n", GetFocus());
3259
3260     SetFocus(0);
3261     flush_sequence();
3262
3263     ShowWindow(mdi_child2, SW_HIDE);
3264     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3265
3266     ShowWindow(mdi_child2, SW_RESTORE);
3267     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3268     flush_sequence();
3269
3270     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3271     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3272
3273     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3274     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3275     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3276     flush_sequence();
3277
3278     SetFocus(0);
3279     flush_sequence();
3280
3281     ShowWindow(mdi_child2, SW_HIDE);
3282     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3283
3284     ShowWindow(mdi_child2, SW_SHOW);
3285     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3286
3287     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3288     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3289
3290     ShowWindow(mdi_child2, SW_MAXIMIZE);
3291     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3292
3293     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3294     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3295
3296     ShowWindow(mdi_child2, SW_RESTORE);
3297     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
3298
3299     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3300     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3301
3302     ShowWindow(mdi_child2, SW_MINIMIZE);
3303     ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
3304
3305     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3306     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3307
3308     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3309     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3310     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3311     flush_sequence();
3312
3313     ShowWindow(mdi_child2, SW_RESTORE);
3314     ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", TRUE);
3315
3316     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3317     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3318
3319     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3320     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3321     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3322     flush_sequence();
3323
3324     SetFocus(0);
3325     flush_sequence();
3326
3327     ShowWindow(mdi_child2, SW_HIDE);
3328     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3329
3330     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3331     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3332
3333     DestroyWindow(mdi_child2);
3334     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
3335
3336     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3337     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3338
3339     /* test for maximized MDI children */
3340     trace("creating maximized visible MDI child window 1\n");
3341     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3342                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3343                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3344                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3345     assert(mdi_child);
3346     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
3347     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3348
3349     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3350     ok(GetFocus() == mdi_child || /* win2k */
3351        GetFocus() == 0, /* win9x */
3352        "wrong focus window %p\n", GetFocus());
3353
3354     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3355     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3356     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3357     flush_sequence();
3358
3359     trace("creating maximized visible MDI child window 2\n");
3360     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3361                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3362                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3363                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3364     assert(mdi_child2);
3365     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3366     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3367     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3368
3369     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3370     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3371
3372     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3373     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3374     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3375     flush_sequence();
3376
3377     trace("destroying maximized visible MDI child window 2\n");
3378     DestroyWindow(mdi_child2);
3379     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3380
3381     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3382
3383     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3384     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3385
3386     /* Win2k: MDI client still returns a just destroyed child as active
3387      * Win9x: MDI client returns 0
3388      */
3389     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3390     ok(active_child == mdi_child2 || /* win2k */
3391        !active_child, /* win9x */
3392        "wrong active MDI child %p\n", active_child);
3393     flush_sequence();
3394
3395     ShowWindow(mdi_child, SW_MAXIMIZE);
3396     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3397     flush_sequence();
3398
3399     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3400     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3401
3402     trace("re-creating maximized visible MDI child window 2\n");
3403     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3404                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3405                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3406                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3407     assert(mdi_child2);
3408     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
3409     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
3410     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
3411
3412     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3413     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
3414
3415     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3416     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3417     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3418     flush_sequence();
3419
3420     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
3421     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
3422     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
3423
3424     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
3425     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3426     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3427
3428     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3429     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3430     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3431     flush_sequence();
3432
3433     DestroyWindow(mdi_child);
3434     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3435
3436     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3437     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3438
3439     /* Win2k: MDI client still returns a just destroyed child as active
3440      * Win9x: MDI client returns 0
3441      */
3442     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3443     ok(active_child == mdi_child || /* win2k */
3444        !active_child, /* win9x */
3445        "wrong active MDI child %p\n", active_child);
3446     flush_sequence();
3447
3448     trace("creating maximized invisible MDI child window\n");
3449     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3450                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
3451                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3452                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3453     assert(mdi_child2);
3454     ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
3455     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3456     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
3457     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
3458
3459     /* Win2k: MDI client still returns a just destroyed child as active
3460      * Win9x: MDI client returns 0
3461      */
3462     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3463     ok(active_child == mdi_child || /* win2k */
3464        !active_child, /* win9x */
3465        "wrong active MDI child %p\n", active_child);
3466     flush_sequence();
3467
3468     trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
3469     ShowWindow(mdi_child2, SW_MAXIMIZE);
3470     ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
3471     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
3472     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3473     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3474
3475     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3476     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3477     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3478     flush_sequence();
3479
3480     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3481     flush_sequence();
3482
3483     /* end of test for maximized MDI children */
3484     SetFocus(0);
3485     flush_sequence();
3486     trace("creating maximized visible MDI child window 1(Switch test)\n");
3487     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3488                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3489                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3490                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3491     assert(mdi_child);
3492     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
3493     ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
3494
3495     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3496     ok(GetFocus() == mdi_child || /* win2k */
3497        GetFocus() == 0, /* win9x */
3498        "wrong focus window %p(Switch test)\n", GetFocus());
3499
3500     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3501     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3502     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3503     flush_sequence();
3504
3505     trace("creating maximized visible MDI child window 2(Switch test)\n");
3506     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3507                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
3508                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3509                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3510     assert(mdi_child2);
3511     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
3512
3513     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
3514     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
3515
3516     ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
3517     ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
3518
3519     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3520     ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
3521     ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
3522     flush_sequence();
3523
3524     trace("Switch child window.\n");
3525     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
3526     ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
3527     trace("end of test for switch maximized MDI children\n");
3528     flush_sequence();
3529
3530     /* Prepare for switching test of not maximized MDI children  */
3531     ShowWindow( mdi_child, SW_NORMAL );
3532     ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
3533     ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
3534     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
3535     ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
3536     flush_sequence();
3537
3538     SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
3539     ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
3540     trace("end of test for switch not maximized MDI children\n");
3541     flush_sequence();
3542
3543     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3544     flush_sequence();
3545
3546     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
3547     flush_sequence();
3548
3549     SetFocus(0);
3550     flush_sequence();
3551     /* end of tests for switch maximized/not maximized MDI children */
3552
3553     mdi_cs.szClass = "MDI_child_Class";
3554     mdi_cs.szTitle = "MDI child";
3555     mdi_cs.hOwner = GetModuleHandleA(0);
3556     mdi_cs.x = 0;
3557     mdi_cs.y = 0;
3558     mdi_cs.cx = CW_USEDEFAULT;
3559     mdi_cs.cy = CW_USEDEFAULT;
3560     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
3561     mdi_cs.lParam = 0;
3562     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
3563     ok(mdi_child != 0, "MDI child creation failed\n");
3564     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
3565
3566     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
3567
3568     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3569     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3570
3571     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
3572     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3573     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3574
3575     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3576     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3577     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3578     flush_sequence();
3579
3580     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
3581     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
3582
3583     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
3584     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3585     ok(!active_child, "wrong active MDI child %p\n", active_child);
3586
3587     SetFocus(0);
3588     flush_sequence();
3589
3590     DestroyWindow(mdi_client);
3591     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3592
3593     /* test maximization of MDI child with invisible parent */
3594     client_cs.hWindowMenu = 0;
3595     mdi_client = CreateWindow("MDI_client_class",
3596                                  NULL,
3597                                  WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
3598                                  0, 0, 660, 430,
3599                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3600     ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
3601
3602     ShowWindow(mdi_client, SW_HIDE);
3603     ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
3604
3605     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3606                                 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
3607                                 0, 0, 650, 440,
3608                                 mdi_client, 0, GetModuleHandleA(0), NULL);
3609     ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
3610
3611     SendMessage(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
3612     ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
3613     zoomed = IsZoomed(mdi_child);
3614     ok(zoomed, "wrong zoomed state %d\n", zoomed);
3615     
3616     ShowWindow(mdi_client, SW_SHOW);
3617     ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
3618
3619     DestroyWindow(mdi_child);
3620     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
3621
3622     /* end of test for maximization of MDI child with invisible parent */
3623
3624     DestroyWindow(mdi_client);
3625     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
3626
3627     DestroyWindow(mdi_frame);
3628     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
3629 }
3630 /************************* End of MDI test **********************************/
3631
3632 static void test_WM_SETREDRAW(HWND hwnd)
3633 {
3634     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
3635
3636     flush_events();
3637     flush_sequence();
3638
3639     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3640     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
3641
3642     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
3643     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
3644
3645     flush_sequence();
3646     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3647     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
3648
3649     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3650     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
3651
3652     /* restore original WS_VISIBLE state */
3653     SetWindowLongA(hwnd, GWL_STYLE, style);
3654
3655     flush_events();
3656     flush_sequence();
3657 }
3658
3659 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3660 {
3661     struct message msg;
3662
3663     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
3664
3665     /* explicitly ignore WM_GETICON message */
3666     if (message == WM_GETICON) return 0;
3667
3668     /* ignore registered messages */
3669     if (message >= 0xc000) return 0;
3670
3671     switch (message)
3672     {
3673         /* ignore */
3674         case WM_MOUSEMOVE:
3675         case WM_SETCURSOR:
3676         case WM_DEVICECHANGE:
3677             return 0;
3678         case WM_NCHITTEST:
3679             return HTCLIENT;
3680
3681         case WM_WINDOWPOSCHANGING:
3682         case WM_WINDOWPOSCHANGED:
3683         {
3684             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
3685
3686             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
3687             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
3688                   winpos->hwnd, winpos->hwndInsertAfter,
3689                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
3690             dump_winpos_flags(winpos->flags);
3691
3692             /* Log only documented flags, win2k uses 0x1000 and 0x2000
3693              * in the high word for internal purposes
3694              */
3695             wParam = winpos->flags & 0xffff;
3696             /* We are not interested in the flags that don't match under XP and Win9x */
3697             wParam &= ~(SWP_NOZORDER);
3698             break;
3699         }
3700     }
3701
3702     msg.message = message;
3703     msg.flags = sent|wparam|lparam;
3704     msg.wParam = wParam;
3705     msg.lParam = lParam;
3706     add_message(&msg);
3707
3708     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
3709     if (message == WM_TIMER) EndDialog( hwnd, 0 );
3710     return 0;
3711 }
3712
3713 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3714 {
3715     DWORD style, exstyle;
3716     INT xmin, xmax;
3717     BOOL ret;
3718
3719     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3720     style = GetWindowLongA(hwnd, GWL_STYLE);
3721     /* do not be confused by WS_DLGFRAME set */
3722     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3723
3724     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3725     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3726
3727     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3728     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3729     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3730         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
3731     else
3732         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
3733
3734     style = GetWindowLongA(hwnd, GWL_STYLE);
3735     if (set) ok(style & set, "style %08x should be set\n", set);
3736     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3737
3738     /* a subsequent call should do nothing */
3739     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
3740     ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
3741     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3742
3743     xmin = 0xdeadbeef;
3744     xmax = 0xdeadbeef;
3745     trace("Ignore GetScrollRange error below if you are on Win9x\n");
3746     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
3747     ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
3748     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3749     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
3750     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
3751 }
3752
3753 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
3754 {
3755     DWORD style, exstyle;
3756     SCROLLINFO si;
3757     BOOL ret;
3758
3759     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
3760     style = GetWindowLongA(hwnd, GWL_STYLE);
3761     /* do not be confused by WS_DLGFRAME set */
3762     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
3763
3764     if (clear) ok(style & clear, "style %08x should be set\n", clear);
3765     if (set) ok(!(style & set), "style %08x should not be set\n", set);
3766
3767     si.cbSize = sizeof(si);
3768     si.fMask = SIF_RANGE;
3769     si.nMin = min;
3770     si.nMax = max;
3771     SetScrollInfo(hwnd, ctl, &si, TRUE);
3772     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
3773         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
3774     else
3775         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
3776
3777     style = GetWindowLongA(hwnd, GWL_STYLE);
3778     if (set) ok(style & set, "style %08x should be set\n", set);
3779     if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
3780
3781     /* a subsequent call should do nothing */
3782     SetScrollInfo(hwnd, ctl, &si, TRUE);
3783     if (style & WS_HSCROLL)
3784         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3785     else if (style & WS_VSCROLL)
3786         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3787     else
3788         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3789
3790     si.fMask = SIF_PAGE;
3791     si.nPage = 5;
3792     SetScrollInfo(hwnd, ctl, &si, FALSE);
3793     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3794
3795     si.fMask = SIF_POS;
3796     si.nPos = max - 1;
3797     SetScrollInfo(hwnd, ctl, &si, FALSE);
3798     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
3799
3800     si.fMask = SIF_RANGE;
3801     si.nMin = 0xdeadbeef;
3802     si.nMax = 0xdeadbeef;
3803     ret = GetScrollInfo(hwnd, ctl, &si);
3804     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3805     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
3806     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
3807     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
3808 }
3809
3810 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
3811 static void test_scroll_messages(HWND hwnd)
3812 {
3813     SCROLLINFO si;
3814     INT min, max;
3815     BOOL ret;
3816
3817     flush_events();
3818     flush_sequence();
3819
3820     min = 0xdeadbeef;
3821     max = 0xdeadbeef;
3822     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3823     ok( ret, "GetScrollRange error %d\n", GetLastError());
3824     if (sequence->message != WmGetScrollRangeSeq[0].message)
3825         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3826     /* values of min and max are undefined */
3827     flush_sequence();
3828
3829     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
3830     ok( ret, "SetScrollRange error %d\n", GetLastError());
3831     if (sequence->message != WmSetScrollRangeSeq[0].message)
3832         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3833     flush_sequence();
3834
3835     min = 0xdeadbeef;
3836     max = 0xdeadbeef;
3837     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
3838     ok( ret, "GetScrollRange error %d\n", GetLastError());
3839     if (sequence->message != WmGetScrollRangeSeq[0].message)
3840         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
3841     /* values of min and max are undefined */
3842     flush_sequence();
3843
3844     si.cbSize = sizeof(si);
3845     si.fMask = SIF_RANGE;
3846     si.nMin = 20;
3847     si.nMax = 160;
3848     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3849     if (sequence->message != WmSetScrollRangeSeq[0].message)
3850         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3851     flush_sequence();
3852
3853     si.fMask = SIF_PAGE;
3854     si.nPage = 10;
3855     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3856     if (sequence->message != WmSetScrollRangeSeq[0].message)
3857         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3858     flush_sequence();
3859
3860     si.fMask = SIF_POS;
3861     si.nPos = 20;
3862     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
3863     if (sequence->message != WmSetScrollRangeSeq[0].message)
3864         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3865     flush_sequence();
3866
3867     si.fMask = SIF_RANGE;
3868     si.nMin = 0xdeadbeef;
3869     si.nMax = 0xdeadbeef;
3870     ret = GetScrollInfo(hwnd, SB_CTL, &si);
3871     ok( ret, "GetScrollInfo error %d\n", GetLastError());
3872     if (sequence->message != WmGetScrollInfoSeq[0].message)
3873         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
3874     /* values of min and max are undefined */
3875     flush_sequence();
3876
3877     /* set WS_HSCROLL */
3878     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3879     /* clear WS_HSCROLL */
3880     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3881
3882     /* set WS_HSCROLL */
3883     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
3884     /* clear WS_HSCROLL */
3885     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
3886
3887     /* set WS_VSCROLL */
3888     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3889     /* clear WS_VSCROLL */
3890     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3891
3892     /* set WS_VSCROLL */
3893     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3894     /* clear WS_VSCROLL */
3895     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3896 }
3897
3898 static void test_showwindow(void)
3899 {
3900     HWND hwnd, hchild;
3901     RECT rc;
3902
3903     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3904                            100, 100, 200, 200, 0, 0, 0, NULL);
3905     ok (hwnd != 0, "Failed to create overlapped window\n");
3906     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3907                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3908     ok (hchild != 0, "Failed to create child\n");
3909     flush_sequence();
3910
3911     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3912     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3913     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3914     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3915     trace("done\n");
3916
3917     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3918     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3919     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3920     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3921     trace("done\n");
3922     /* back to invisible */
3923     ShowWindow(hchild, SW_HIDE);
3924     ShowWindow(hwnd, SW_HIDE);
3925     flush_sequence();
3926     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3927     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3928     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3929     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3930     trace("done\n");
3931     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3932     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3933     flush_sequence();
3934     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3935     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3936     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3937     trace("done\n");
3938     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3939     ShowWindow( hwnd, SW_SHOW);
3940     flush_sequence();
3941     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3942     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3943     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3944     trace("done\n");
3945
3946     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3947     ShowWindow( hchild, SW_HIDE);
3948     flush_sequence();
3949     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3950     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3951     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3952     trace("done\n");
3953
3954     SetCapture(hchild);
3955     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3956     DestroyWindow(hchild);
3957     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3958
3959     DestroyWindow(hwnd);
3960     flush_sequence();
3961
3962     /* Popup windows */
3963     /* Test 1:
3964      * 1. Create invisible maximized popup window.
3965      * 2. Move and resize it.
3966      * 3. Show it maximized.
3967      */
3968     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3969     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3970                            100, 100, 200, 200, 0, 0, 0, NULL);
3971     ok (hwnd != 0, "Failed to create popup window\n");
3972     ok(IsZoomed(hwnd), "window should be maximized\n");
3973     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3974     trace("done\n");
3975
3976     GetWindowRect(hwnd, &rc);
3977     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3978         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3979         "Invalid maximized size before ShowWindow (%d,%d)-(%d,%d)\n",
3980         rc.left, rc.top, rc.right, rc.bottom);
3981     /* Reset window's size & position */
3982     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3983     ok(IsZoomed(hwnd), "window should be maximized\n");
3984     flush_sequence();
3985
3986     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
3987     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3988     ok(IsZoomed(hwnd), "window should be maximized\n");
3989     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
3990     trace("done\n");
3991
3992     GetWindowRect(hwnd, &rc);
3993     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3994         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3995         "Invalid maximized size after ShowWindow (%d,%d)-(%d,%d)\n",
3996         rc.left, rc.top, rc.right, rc.bottom);
3997     DestroyWindow(hwnd);
3998     flush_sequence();
3999
4000     /* Test 2:
4001      * 1. Create invisible maximized popup window.
4002      * 2. Show it maximized.
4003      */
4004     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4005     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4006                            100, 100, 200, 200, 0, 0, 0, NULL);
4007     ok (hwnd != 0, "Failed to create popup window\n");
4008     ok(IsZoomed(hwnd), "window should be maximized\n");
4009     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4010     trace("done\n");
4011
4012     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4013     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4014     ok(IsZoomed(hwnd), "window should be maximized\n");
4015     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4016     trace("done\n");
4017     DestroyWindow(hwnd);
4018     flush_sequence();
4019
4020     /* Test 3:
4021      * 1. Create visible maximized popup window.
4022      */
4023     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4024     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4025                            100, 100, 200, 200, 0, 0, 0, NULL);
4026     ok (hwnd != 0, "Failed to create popup window\n");
4027     ok(IsZoomed(hwnd), "window should be maximized\n");
4028     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4029     trace("done\n");
4030     DestroyWindow(hwnd);
4031     flush_sequence();
4032
4033     /* Test 4:
4034      * 1. Create visible popup window.
4035      * 2. Maximize it.
4036      */
4037     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4038     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4039                            100, 100, 200, 200, 0, 0, 0, NULL);
4040     ok (hwnd != 0, "Failed to create popup window\n");
4041     ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4042     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4043     trace("done\n");
4044
4045     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4046     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4047     ok(IsZoomed(hwnd), "window should be maximized\n");
4048     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4049     trace("done\n");
4050     DestroyWindow(hwnd);
4051     flush_sequence();
4052 }
4053
4054 static void test_sys_menu(void)
4055 {
4056     HWND hwnd;
4057     HMENU hmenu;
4058     UINT state;
4059
4060     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4061                            100, 100, 200, 200, 0, 0, 0, NULL);
4062     ok (hwnd != 0, "Failed to create overlapped window\n");
4063
4064     flush_sequence();
4065
4066     /* test existing window without CS_NOCLOSE style */
4067     hmenu = GetSystemMenu(hwnd, FALSE);
4068     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4069
4070     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4071     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4072     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4073
4074     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4075     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4076
4077     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4078     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4079     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4080
4081     EnableMenuItem(hmenu, SC_CLOSE, 0);
4082     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4083
4084     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4085     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4086     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4087
4088     /* test whether removing WS_SYSMENU destroys a system menu */
4089     SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4090     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4091     flush_sequence();
4092     hmenu = GetSystemMenu(hwnd, FALSE);
4093     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4094
4095     DestroyWindow(hwnd);
4096
4097     /* test new window with CS_NOCLOSE style */
4098     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4099                            100, 100, 200, 200, 0, 0, 0, NULL);
4100     ok (hwnd != 0, "Failed to create overlapped window\n");
4101
4102     hmenu = GetSystemMenu(hwnd, FALSE);
4103     ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4104
4105     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4106     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4107
4108     DestroyWindow(hwnd);
4109
4110     /* test new window without WS_SYSMENU style */
4111     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4112                            100, 100, 200, 200, 0, 0, 0, NULL);
4113     ok(hwnd != 0, "Failed to create overlapped window\n");
4114
4115     hmenu = GetSystemMenu(hwnd, FALSE);
4116     ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4117
4118     DestroyWindow(hwnd);
4119 }
4120
4121 /* For shown WS_OVERLAPPEDWINDOW */
4122 static const struct message WmSetIcon_1[] = {
4123     { WM_SETICON, sent },
4124     { 0x00AE, sent|defwinproc|optional }, /* XP */
4125     { WM_GETTEXT, sent|defwinproc|optional },
4126     { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4127     { 0 }
4128 };
4129
4130 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4131 static const struct message WmSetIcon_2[] = {
4132     { WM_SETICON, sent },
4133     { 0 }
4134 };
4135
4136 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4137 static const struct message WmInitEndSession[] = {
4138     { 0x003B, sent },
4139     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4140     { 0 }
4141 };
4142
4143 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4144 static const struct message WmInitEndSession_2[] = {
4145     { 0x003B, sent },
4146     { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4147     { 0 }
4148 };
4149
4150 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4151 static const struct message WmInitEndSession_3[] = {
4152     { 0x003B, sent },
4153     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4154     { 0 }
4155 };
4156
4157 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4158 static const struct message WmInitEndSession_4[] = {
4159     { 0x003B, sent },
4160     { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4161     { 0 }
4162 };
4163
4164 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4165 static const struct message WmInitEndSession_5[] = {
4166     { 0x003B, sent },
4167     { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4168     { 0 }
4169 };
4170
4171 static const struct message WmZOrder[] = {
4172     { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4173     { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4174     { HCBT_ACTIVATE, hook },
4175     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4176     { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4177     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4178     { WM_GETTEXT, sent|optional },
4179     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4180     { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4181     { WM_NCACTIVATE, sent|wparam|lparam, 1, 0 },
4182     { WM_GETTEXT, sent|defwinproc|optional },
4183     { WM_GETTEXT, sent|defwinproc|optional },
4184     { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4185     { HCBT_SETFOCUS, hook },
4186     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4187     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4188     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4189     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4190     { WM_GETTEXT, sent|optional },
4191     { WM_NCCALCSIZE, sent|optional },
4192     { 0 }
4193 };
4194
4195 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4196 {
4197     DWORD ret;
4198     MSG msg;
4199
4200     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4201     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4202
4203     PostMessageA(hwnd, WM_USER, 0, 0);
4204
4205     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4206     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4207
4208     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4209     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4210
4211     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4212     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4213
4214     PostMessageA(hwnd, WM_USER, 0, 0);
4215
4216     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4217     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4218
4219     ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4220     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4221
4222     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4223     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4224     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4225
4226     PostMessageA(hwnd, WM_USER, 0, 0);
4227
4228     /* new incoming message causes it to become signaled again */
4229     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4230     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4231
4232     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4233     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4234     ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4235     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4236 }
4237
4238 /* test if we receive the right sequence of messages */
4239 static void test_messages(void)
4240 {
4241     HWND hwnd, hparent, hchild;
4242     HWND hchild2, hbutton;
4243     HMENU hmenu;
4244     MSG msg;
4245     LRESULT res;
4246
4247     flush_sequence();
4248
4249     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4250                            100, 100, 200, 200, 0, 0, 0, NULL);
4251     ok (hwnd != 0, "Failed to create overlapped window\n");
4252     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4253
4254     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
4255     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
4256     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
4257
4258     /* test WM_SETREDRAW on a not visible top level window */
4259     test_WM_SETREDRAW(hwnd);
4260
4261     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4262     flush_events();
4263     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
4264     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
4265
4266     ok(GetActiveWindow() == hwnd, "window should be active\n");
4267     ok(GetFocus() == hwnd, "window should have input focus\n");
4268     ShowWindow(hwnd, SW_HIDE);
4269     flush_events();
4270     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4271
4272     ShowWindow(hwnd, SW_SHOW);
4273     flush_events();
4274     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
4275
4276     ShowWindow(hwnd, SW_HIDE);
4277     flush_events();
4278     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
4279
4280     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4281     flush_events();
4282     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
4283
4284     ShowWindow(hwnd, SW_RESTORE);
4285     ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
4286     flush_events();
4287     flush_sequence();
4288
4289     ShowWindow(hwnd, SW_MINIMIZE);
4290     flush_events();
4291     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
4292     flush_sequence();
4293
4294     ShowWindow(hwnd, SW_RESTORE);
4295     flush_events();
4296     ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
4297     flush_sequence();
4298
4299     ShowWindow(hwnd, SW_SHOW);
4300     flush_events();
4301     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
4302
4303     ok(GetActiveWindow() == hwnd, "window should be active\n");
4304     ok(GetFocus() == hwnd, "window should have input focus\n");
4305     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4306     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
4307     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
4308     ok(GetActiveWindow() == hwnd, "window should still be active\n");
4309
4310     /* test WM_SETREDRAW on a visible top level window */
4311     ShowWindow(hwnd, SW_SHOW);
4312     flush_events();
4313     test_WM_SETREDRAW(hwnd);
4314
4315     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
4316     test_scroll_messages(hwnd);
4317
4318     /* test resizing and moving */
4319     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
4320     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
4321     flush_events();
4322     flush_sequence();
4323     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
4324     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
4325     flush_events();
4326     flush_sequence();
4327     SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
4328     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
4329     flush_events();
4330     flush_sequence();
4331
4332     /* popups don't get WM_GETMINMAXINFO */
4333     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
4334     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4335     flush_sequence();
4336     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
4337     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
4338
4339     DestroyWindow(hwnd);
4340     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
4341
4342     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4343                               100, 100, 200, 200, 0, 0, 0, NULL);
4344     ok (hparent != 0, "Failed to create parent window\n");
4345     flush_sequence();
4346
4347     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
4348                              0, 0, 10, 10, hparent, 0, 0, NULL);
4349     ok (hchild != 0, "Failed to create child window\n");
4350     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
4351     DestroyWindow(hchild);
4352     flush_sequence();
4353
4354     /* visible child window with a caption */
4355     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
4356                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
4357                              0, 0, 10, 10, hparent, 0, 0, NULL);
4358     ok (hchild != 0, "Failed to create child window\n");
4359     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
4360
4361     trace("testing scroll APIs on a visible child window %p\n", hchild);
4362     test_scroll_messages(hchild);
4363
4364     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4365     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
4366
4367     DestroyWindow(hchild);
4368     flush_sequence();
4369
4370     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4371                              0, 0, 10, 10, hparent, 0, 0, NULL);
4372     ok (hchild != 0, "Failed to create child window\n");
4373     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4374     
4375     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
4376                                100, 100, 50, 50, hparent, 0, 0, NULL);
4377     ok (hchild2 != 0, "Failed to create child2 window\n");
4378     flush_sequence();
4379
4380     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
4381                               0, 100, 50, 50, hchild, 0, 0, NULL);
4382     ok (hbutton != 0, "Failed to create button window\n");
4383
4384     /* test WM_SETREDRAW on a not visible child window */
4385     test_WM_SETREDRAW(hchild);
4386
4387     ShowWindow(hchild, SW_SHOW);
4388     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4389
4390     /* check parent messages too */
4391     log_all_parent_messages++;
4392     ShowWindow(hchild, SW_HIDE);
4393     ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
4394     log_all_parent_messages--;
4395
4396     ShowWindow(hchild, SW_SHOW);
4397     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4398
4399     ShowWindow(hchild, SW_HIDE);
4400     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
4401
4402     ShowWindow(hchild, SW_SHOW);
4403     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
4404
4405     /* test WM_SETREDRAW on a visible child window */
4406     test_WM_SETREDRAW(hchild);
4407
4408     log_all_parent_messages++;
4409     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
4410     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
4411     log_all_parent_messages--;
4412
4413     ShowWindow(hchild, SW_HIDE);
4414     flush_sequence();
4415     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4416     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
4417
4418     ShowWindow(hchild, SW_HIDE);
4419     flush_sequence();
4420     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
4421     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
4422
4423     /* DestroyWindow sequence below expects that a child has focus */
4424     SetFocus(hchild);
4425     flush_sequence();
4426
4427     DestroyWindow(hchild);
4428     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
4429     DestroyWindow(hchild2);
4430     DestroyWindow(hbutton);
4431
4432     flush_sequence();
4433     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
4434                              0, 0, 100, 100, hparent, 0, 0, NULL);
4435     ok (hchild != 0, "Failed to create child popup window\n");
4436     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
4437     DestroyWindow(hchild);
4438
4439     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
4440     flush_sequence();
4441     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
4442                              0, 0, 100, 100, hparent, 0, 0, NULL);
4443     ok (hchild != 0, "Failed to create popup window\n");
4444     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4445     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4446     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4447     flush_sequence();
4448     ShowWindow(hchild, SW_SHOW);
4449     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4450     flush_sequence();
4451     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4452     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4453     flush_sequence();
4454     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
4455     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
4456     DestroyWindow(hchild);
4457
4458     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
4459      * changes nothing in message sequences.
4460      */
4461     flush_sequence();
4462     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
4463                              0, 0, 100, 100, hparent, 0, 0, NULL);
4464     ok (hchild != 0, "Failed to create popup window\n");
4465     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
4466     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4467     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
4468     flush_sequence();
4469     ShowWindow(hchild, SW_SHOW);
4470     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
4471     flush_sequence();
4472     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4473     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
4474     DestroyWindow(hchild);
4475
4476     flush_sequence();
4477     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
4478                            0, 0, 100, 100, hparent, 0, 0, NULL);
4479     ok(hwnd != 0, "Failed to create custom dialog window\n");
4480     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
4481
4482     /*
4483     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
4484     test_scroll_messages(hwnd);
4485     */
4486
4487     flush_sequence();
4488
4489     test_def_id = 1;
4490     SendMessage(hwnd, WM_NULL, 0, 0);
4491
4492     flush_sequence();
4493     after_end_dialog = 1;
4494     EndDialog( hwnd, 0 );
4495     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
4496
4497     DestroyWindow(hwnd);
4498     after_end_dialog = 0;
4499     test_def_id = 0;
4500
4501     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
4502                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
4503     ok(hwnd != 0, "Failed to create custom dialog window\n");
4504     flush_sequence();
4505     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
4506     ShowWindow(hwnd, SW_SHOW);
4507     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
4508     DestroyWindow(hwnd);
4509
4510     flush_sequence();
4511     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
4512     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
4513
4514     DestroyWindow(hparent);
4515     flush_sequence();
4516
4517     /* Message sequence for SetMenu */
4518     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
4519     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
4520
4521     hmenu = CreateMenu();
4522     ok (hmenu != 0, "Failed to create menu\n");
4523     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
4524     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4525                            100, 100, 200, 200, 0, hmenu, 0, NULL);
4526     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
4527     ok (SetMenu(hwnd, 0), "SetMenu\n");
4528     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
4529     ok (SetMenu(hwnd, 0), "SetMenu\n");
4530     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
4531     ShowWindow(hwnd, SW_SHOW);
4532     UpdateWindow( hwnd );
4533     flush_events();
4534     flush_sequence();
4535     ok (SetMenu(hwnd, 0), "SetMenu\n");
4536     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
4537     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
4538     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
4539
4540     UpdateWindow( hwnd );
4541     flush_events();
4542     flush_sequence();
4543     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
4544     flush_events();
4545     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
4546
4547     DestroyWindow(hwnd);
4548     flush_sequence();
4549
4550     /* Message sequence for EnableWindow */
4551     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4552                               100, 100, 200, 200, 0, 0, 0, NULL);
4553     ok (hparent != 0, "Failed to create parent window\n");
4554     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
4555                              0, 0, 10, 10, hparent, 0, 0, NULL);
4556     ok (hchild != 0, "Failed to create child window\n");
4557
4558     SetFocus(hchild);
4559     flush_events();
4560     flush_sequence();
4561
4562     EnableWindow(hparent, FALSE);
4563     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
4564
4565     EnableWindow(hparent, TRUE);
4566     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
4567
4568     flush_events();
4569     flush_sequence();
4570
4571     test_MsgWaitForMultipleObjects(hparent);
4572
4573     /* the following test causes an exception in user.exe under win9x */
4574     if (!PostMessageW( hparent, WM_USER, 0, 0 ))
4575     {
4576         DestroyWindow(hparent);
4577         flush_sequence();
4578         return;
4579     }
4580     PostMessageW( hparent, WM_USER+1, 0, 0 );
4581     /* PeekMessage(NULL) fails, but still removes the message */
4582     SetLastError(0xdeadbeef);
4583     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
4584     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
4585         GetLastError() == 0xdeadbeef, /* NT4 */
4586         "last error is %d\n", GetLastError() );
4587     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
4588     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
4589
4590     DestroyWindow(hchild);
4591     DestroyWindow(hparent);
4592     flush_sequence();
4593
4594     /* Message sequences for WM_SETICON */
4595     trace("testing WM_SETICON\n");
4596     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4597                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4598                            NULL, NULL, 0);
4599     ShowWindow(hwnd, SW_SHOW);
4600     UpdateWindow(hwnd);
4601     flush_events();
4602     flush_sequence();
4603     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4604     ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
4605
4606     ShowWindow(hwnd, SW_HIDE);
4607     flush_events();
4608     flush_sequence();
4609     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4610     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
4611     DestroyWindow(hwnd);
4612     flush_sequence();
4613
4614     hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
4615                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
4616                            NULL, NULL, 0);
4617     ShowWindow(hwnd, SW_SHOW);
4618     UpdateWindow(hwnd);
4619     flush_events();
4620     flush_sequence();
4621     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4622     ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
4623
4624     ShowWindow(hwnd, SW_HIDE);
4625     flush_events();
4626     flush_sequence();
4627     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(0, IDI_APPLICATION));
4628     ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
4629
4630     flush_sequence();
4631     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
4632     if (!res)
4633     {
4634         todo_wine win_skip( "Message 0x3b not supported\n" );
4635         goto done;
4636     }
4637     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
4638     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
4639     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
4640     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
4641     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
4642     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
4643     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
4644     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
4645
4646     flush_sequence();
4647     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
4648     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
4649     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
4650     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
4651     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
4652     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
4653
4654     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
4655     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
4656     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
4657
4658     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
4659     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
4660     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
4661
4662 done:
4663     DestroyWindow(hwnd);
4664     flush_sequence();
4665 }
4666
4667 static void test_setwindowpos(void)
4668 {
4669     HWND hwnd;
4670     RECT rc;
4671     LRESULT res;
4672     const INT winX = 100;
4673     const INT winY = 100;
4674     const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
4675
4676     hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
4677                            0, 0, winX, winY, 0,
4678                            NULL, NULL, 0);
4679
4680     GetWindowRect(hwnd, &rc);
4681     expect(sysX, rc.right);
4682     expect(winY, rc.bottom);
4683
4684     flush_events();
4685     flush_sequence();
4686     res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
4687     ok_sequence(WmZOrder, "Z-Order", TRUE);
4688     ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
4689
4690     GetWindowRect(hwnd, &rc);
4691     expect(sysX, rc.right);
4692     expect(winY, rc.bottom);
4693     DestroyWindow(hwnd);
4694 }
4695
4696 static void invisible_parent_tests(void)
4697 {
4698     HWND hparent, hchild;
4699
4700     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4701                               100, 100, 200, 200, 0, 0, 0, NULL);
4702     ok (hparent != 0, "Failed to create parent window\n");
4703     flush_sequence();
4704
4705     /* test showing child with hidden parent */
4706
4707     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4708                              0, 0, 10, 10, hparent, 0, 0, NULL);
4709     ok (hchild != 0, "Failed to create child window\n");
4710     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
4711
4712     ShowWindow( hchild, SW_MINIMIZE );
4713     ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4714     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4715     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4716
4717     /* repeat */
4718     flush_events();
4719     flush_sequence();
4720     ShowWindow( hchild, SW_MINIMIZE );
4721     ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
4722
4723     DestroyWindow(hchild);
4724     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4725                              0, 0, 10, 10, hparent, 0, 0, NULL);
4726     flush_sequence();
4727
4728     ShowWindow( hchild, SW_MAXIMIZE );
4729     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4730     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4731     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4732
4733     /* repeat */
4734     flush_events();
4735     flush_sequence();
4736     ShowWindow( hchild, SW_MAXIMIZE );
4737     ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
4738
4739     DestroyWindow(hchild);
4740     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4741                              0, 0, 10, 10, hparent, 0, 0, NULL);
4742     flush_sequence();
4743
4744     ShowWindow( hchild, SW_RESTORE );
4745     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
4746     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4747     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4748
4749     DestroyWindow(hchild);
4750     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4751                              0, 0, 10, 10, hparent, 0, 0, NULL);
4752     flush_sequence();
4753
4754     ShowWindow( hchild, SW_SHOWMINIMIZED );
4755     ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4756     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4757     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4758
4759     /* repeat */
4760     flush_events();
4761     flush_sequence();
4762     ShowWindow( hchild, SW_SHOWMINIMIZED );
4763     ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
4764
4765     DestroyWindow(hchild);
4766     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4767                              0, 0, 10, 10, hparent, 0, 0, NULL);
4768     flush_sequence();
4769
4770     /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
4771     ShowWindow( hchild, SW_SHOWMAXIMIZED );
4772     ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
4773     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4774     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4775
4776     DestroyWindow(hchild);
4777     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4778                              0, 0, 10, 10, hparent, 0, 0, NULL);
4779     flush_sequence();
4780
4781     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4782     ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4783     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4784     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4785
4786     /* repeat */
4787     flush_events();
4788     flush_sequence();
4789     ShowWindow( hchild, SW_SHOWMINNOACTIVE );
4790     ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
4791
4792     DestroyWindow(hchild);
4793     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4794                              0, 0, 10, 10, hparent, 0, 0, NULL);
4795     flush_sequence();
4796
4797     /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
4798     ShowWindow( hchild, SW_FORCEMINIMIZE );
4799     ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
4800 todo_wine {
4801     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4802 }
4803     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4804
4805     DestroyWindow(hchild);
4806     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4807                              0, 0, 10, 10, hparent, 0, 0, NULL);
4808     flush_sequence();
4809
4810     ShowWindow( hchild, SW_SHOWNA );
4811     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4812     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4813     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4814
4815     /* repeat */
4816     flush_events();
4817     flush_sequence();
4818     ShowWindow( hchild, SW_SHOWNA );
4819     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
4820
4821     DestroyWindow(hchild);
4822     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4823                              0, 0, 10, 10, hparent, 0, 0, NULL);
4824     flush_sequence();
4825
4826     ShowWindow( hchild, SW_SHOW );
4827     ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4828     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4829     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4830
4831     /* repeat */
4832     flush_events();
4833     flush_sequence();
4834     ShowWindow( hchild, SW_SHOW );
4835     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
4836
4837     ShowWindow( hchild, SW_HIDE );
4838     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
4839     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
4840     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4841
4842     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4843     ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
4844     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4845     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4846
4847     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4848     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
4849     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
4850     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
4851
4852     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
4853     flush_sequence();
4854     DestroyWindow(hchild);
4855     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
4856
4857     DestroyWindow(hparent);
4858     flush_sequence();
4859 }
4860
4861 /****************** button message test *************************/
4862 static const struct message WmSetFocusButtonSeq[] =
4863 {
4864     { HCBT_SETFOCUS, hook },
4865     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4866     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4867     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4868     { WM_SETFOCUS, sent|wparam, 0 },
4869     { WM_CTLCOLORBTN, sent|defwinproc },
4870     { 0 }
4871 };
4872 static const struct message WmKillFocusButtonSeq[] =
4873 {
4874     { HCBT_SETFOCUS, hook },
4875     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4876     { WM_KILLFOCUS, sent|wparam, 0 },
4877     { WM_CTLCOLORBTN, sent|defwinproc },
4878     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4879     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4880     { 0 }
4881 };
4882 static const struct message WmSetFocusStaticSeq[] =
4883 {
4884     { HCBT_SETFOCUS, hook },
4885     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
4886     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4887     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4888     { WM_SETFOCUS, sent|wparam, 0 },
4889     { WM_CTLCOLORSTATIC, sent|defwinproc },
4890     { 0 }
4891 };
4892 static const struct message WmKillFocusStaticSeq[] =
4893 {
4894     { HCBT_SETFOCUS, hook },
4895     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4896     { WM_KILLFOCUS, sent|wparam, 0 },
4897     { WM_CTLCOLORSTATIC, sent|defwinproc },
4898     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
4899     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
4900     { 0 }
4901 };
4902 static const struct message WmLButtonDownSeq[] =
4903 {
4904     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
4905     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4906     { HCBT_SETFOCUS, hook },
4907     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4908     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4909     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4910     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4911     { WM_CTLCOLORBTN, sent|defwinproc },
4912     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
4913     { WM_CTLCOLORBTN, sent|defwinproc },
4914     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4915     { 0 }
4916 };
4917 static const struct message WmLButtonUpSeq[] =
4918 {
4919     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
4920     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
4921     { WM_CTLCOLORBTN, sent|defwinproc },
4922     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
4923     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4924     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
4925     { 0 }
4926 };
4927 static const struct message WmSetFontButtonSeq[] =
4928 {
4929     { WM_SETFONT, sent },
4930     { WM_PAINT, sent },
4931     { WM_ERASEBKGND, sent|defwinproc|optional },
4932     { WM_CTLCOLORBTN, sent|defwinproc },
4933     { 0 }
4934 };
4935
4936 static WNDPROC old_button_proc;
4937
4938 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4939 {
4940     static long defwndproc_counter = 0;
4941     LRESULT ret;
4942     struct message msg;
4943
4944     trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
4945
4946     /* explicitly ignore WM_GETICON message */
4947     if (message == WM_GETICON) return 0;
4948
4949     /* ignore registered messages */
4950     if (message >= 0xc000) return 0;
4951
4952     msg.message = message;
4953     msg.flags = sent|wparam|lparam;
4954     if (defwndproc_counter) msg.flags |= defwinproc;
4955     msg.wParam = wParam;
4956     msg.lParam = lParam;
4957     add_message(&msg);
4958
4959     if (message == BM_SETSTATE)
4960         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
4961
4962     defwndproc_counter++;
4963     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
4964     defwndproc_counter--;
4965
4966     return ret;
4967 }
4968
4969 static void subclass_button(void)
4970 {
4971     WNDCLASSA cls;
4972
4973     if (!GetClassInfoA(0, "button", &cls)) assert(0);
4974
4975     old_button_proc = cls.lpfnWndProc;
4976
4977     cls.hInstance = GetModuleHandle(0);
4978     cls.lpfnWndProc = button_hook_proc;
4979     cls.lpszClassName = "my_button_class";
4980     UnregisterClass(cls.lpszClassName, cls.hInstance);
4981     if (!RegisterClassA(&cls)) assert(0);
4982 }
4983
4984 static void test_button_messages(void)
4985 {
4986     static const struct
4987     {
4988         DWORD style;
4989         DWORD dlg_code;
4990         const struct message *setfocus;
4991         const struct message *killfocus;
4992     } button[] = {
4993         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
4994           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4995         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
4996           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
4997         { BS_CHECKBOX, DLGC_BUTTON,
4998           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
4999         { BS_AUTOCHECKBOX, DLGC_BUTTON,
5000           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5001         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5002           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5003         { BS_3STATE, DLGC_BUTTON,
5004           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5005         { BS_AUTO3STATE, DLGC_BUTTON,
5006           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5007         { BS_GROUPBOX, DLGC_STATIC,
5008           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5009         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
5010           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
5011         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
5012           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
5013         { BS_OWNERDRAW, DLGC_BUTTON,
5014           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
5015     };
5016     unsigned int i;
5017     HWND hwnd;
5018     DWORD dlg_code;
5019     HFONT zfont;
5020
5021     subclass_button();
5022
5023     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
5024     {
5025         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
5026                                0, 0, 50, 14, 0, 0, 0, NULL);
5027         ok(hwnd != 0, "Failed to create button window\n");
5028
5029         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5030         ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5031
5032         ShowWindow(hwnd, SW_SHOW);
5033         UpdateWindow(hwnd);
5034         SetFocus(0);
5035         flush_sequence();
5036
5037         trace("button style %08x\n", button[i].style);
5038         SetFocus(hwnd);
5039         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
5040
5041         SetFocus(0);
5042         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
5043
5044         DestroyWindow(hwnd);
5045     }
5046
5047     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
5048                            0, 0, 50, 14, 0, 0, 0, NULL);
5049     ok(hwnd != 0, "Failed to create button window\n");
5050
5051     SetFocus(0);
5052     flush_events();
5053     flush_sequence();
5054
5055     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
5056     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
5057
5058     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
5059     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
5060
5061     flush_sequence();
5062     zfont = GetStockObject(SYSTEM_FONT);
5063     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
5064     UpdateWindow(hwnd);
5065     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
5066
5067     DestroyWindow(hwnd);
5068 }
5069
5070 /****************** static message test *************************/
5071 static const struct message WmSetFontStaticSeq[] =
5072 {
5073     { WM_SETFONT, sent },
5074     { WM_PAINT, sent|defwinproc },
5075     { WM_ERASEBKGND, sent|defwinproc|optional },
5076     { WM_CTLCOLORSTATIC, sent|defwinproc },
5077     { 0 }
5078 };
5079
5080 static WNDPROC old_static_proc;
5081
5082 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5083 {
5084     static long defwndproc_counter = 0;
5085     LRESULT ret;
5086     struct message msg;
5087
5088     trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5089
5090     /* explicitly ignore WM_GETICON message */
5091     if (message == WM_GETICON) return 0;
5092
5093     /* ignore registered messages */
5094     if (message >= 0xc000) return 0;
5095
5096     msg.message = message;
5097     msg.flags = sent|wparam|lparam;
5098     if (defwndproc_counter) msg.flags |= defwinproc;
5099     msg.wParam = wParam;
5100     msg.lParam = lParam;
5101     add_message(&msg);
5102
5103     defwndproc_counter++;
5104     ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
5105     defwndproc_counter--;
5106
5107     return ret;
5108 }
5109
5110 static void subclass_static(void)
5111 {
5112     WNDCLASSA cls;
5113
5114     if (!GetClassInfoA(0, "static", &cls)) assert(0);
5115
5116     old_static_proc = cls.lpfnWndProc;
5117
5118     cls.hInstance = GetModuleHandle(0);
5119     cls.lpfnWndProc = static_hook_proc;
5120     cls.lpszClassName = "my_static_class";
5121     UnregisterClass(cls.lpszClassName, cls.hInstance);
5122     if (!RegisterClassA(&cls)) assert(0);
5123 }
5124
5125 static void test_static_messages(void)
5126 {
5127     /* FIXME: make as comprehensive as the button message test */
5128     static const struct
5129     {
5130         DWORD style;
5131         DWORD dlg_code;
5132         const struct message *setfont;
5133     } static_ctrl[] = {
5134         { SS_LEFT, DLGC_STATIC,
5135           WmSetFontStaticSeq }
5136     };
5137     unsigned int i;
5138     HWND hwnd;
5139     DWORD dlg_code;
5140
5141     subclass_static();
5142
5143     for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
5144     {
5145         hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
5146                                0, 0, 50, 14, 0, 0, 0, NULL);
5147         ok(hwnd != 0, "Failed to create static window\n");
5148
5149         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
5150         ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
5151
5152         ShowWindow(hwnd, SW_SHOW);
5153         UpdateWindow(hwnd);
5154         SetFocus(0);
5155         flush_sequence();
5156
5157         trace("static style %08x\n", static_ctrl[i].style);
5158         SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
5159         ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
5160
5161         DestroyWindow(hwnd);
5162     }
5163 }
5164
5165 /****************** ComboBox message test *************************/
5166 #define ID_COMBOBOX 0x000f
5167
5168 static const struct message WmKeyDownComboSeq[] =
5169 {
5170     { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
5171     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
5172     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
5173     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
5174     { WM_CTLCOLOREDIT, sent|parent },
5175     { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
5176     { 0 }
5177 };
5178
5179 static WNDPROC old_combobox_proc;
5180
5181 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5182 {
5183     static long defwndproc_counter = 0;
5184     LRESULT ret;
5185     struct message msg;
5186
5187     /* do not log painting messages */
5188     if (message != WM_PAINT &&
5189         message != WM_NCPAINT &&
5190         message != WM_SYNCPAINT &&
5191         message != WM_ERASEBKGND &&
5192         message != WM_NCHITTEST &&
5193         message != WM_GETTEXT &&
5194         message != WM_GETICON &&
5195         message != WM_DEVICECHANGE)
5196     {
5197         trace("combo: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5198
5199         msg.message = message;
5200         msg.flags = sent|wparam|lparam;
5201         if (defwndproc_counter) msg.flags |= defwinproc;
5202         msg.wParam = wParam;
5203         msg.lParam = lParam;
5204         add_message(&msg);
5205     }
5206
5207     defwndproc_counter++;
5208     ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
5209     defwndproc_counter--;
5210
5211     return ret;
5212 }
5213
5214 static void subclass_combobox(void)
5215 {
5216     WNDCLASSA cls;
5217
5218     if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
5219
5220     old_combobox_proc = cls.lpfnWndProc;
5221
5222     cls.hInstance = GetModuleHandle(0);
5223     cls.lpfnWndProc = combobox_hook_proc;
5224     cls.lpszClassName = "my_combobox_class";
5225     UnregisterClass(cls.lpszClassName, cls.hInstance);
5226     if (!RegisterClassA(&cls)) assert(0);
5227 }
5228
5229 static void test_combobox_messages(void)
5230 {
5231     HWND parent, combo;
5232     LRESULT ret;
5233
5234     subclass_combobox();
5235
5236     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5237                              100, 100, 200, 200, 0, 0, 0, NULL);
5238     ok(parent != 0, "Failed to create parent window\n");
5239     flush_sequence();
5240
5241     combo = CreateWindowEx(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
5242                            0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
5243     ok(combo != 0, "Failed to create combobox window\n");
5244
5245     UpdateWindow(combo);
5246
5247     ret = SendMessage(combo, WM_GETDLGCODE, 0, 0);
5248     ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
5249
5250     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
5251     ok(ret == 0, "expected 0, got %ld\n", ret);
5252     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
5253     ok(ret == 1, "expected 1, got %ld\n", ret);
5254     ret = SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
5255     ok(ret == 2, "expected 2, got %ld\n", ret);
5256
5257     SendMessage(combo, CB_SETCURSEL, 0, 0);
5258     SetFocus(combo);
5259     flush_sequence();
5260
5261     log_all_parent_messages++;
5262     SendMessage(combo, WM_KEYDOWN, VK_DOWN, 0);
5263     SendMessage(combo, WM_KEYUP, VK_DOWN, 0);
5264     log_all_parent_messages--;
5265     ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
5266
5267     DestroyWindow(combo);
5268     DestroyWindow(parent);
5269 }
5270
5271 /****************** WM_IME_KEYDOWN message test *******************/
5272
5273 static const struct message WmImeKeydownMsgSeq_0[] =
5274 {
5275     { WM_IME_KEYDOWN, wparam, VK_RETURN },
5276     { WM_CHAR, wparam, 'A' },
5277     { 0 }
5278 };
5279
5280 static const struct message WmImeKeydownMsgSeq_1[] =
5281 {
5282     { WM_KEYDOWN, optional|wparam, VK_RETURN },
5283     { WM_CHAR,    optional|wparam, VK_RETURN },
5284     { 0 }
5285 };
5286
5287 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5288 {
5289     struct message msg;
5290
5291     trace("wmime_keydown_procA: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
5292
5293     msg.message = message;
5294     msg.flags = wparam|lparam;
5295     msg.wParam = wParam;
5296     msg.lParam = lParam;
5297     add_message(&msg);
5298
5299     return DefWindowProcA(hwnd, message, wParam, lParam);
5300 }
5301
5302 static void register_wmime_keydown_class(void)
5303 {
5304     WNDCLASSA cls;
5305
5306     ZeroMemory(&cls, sizeof(WNDCLASSA));
5307     cls.lpfnWndProc = wmime_keydown_procA;
5308     cls.hInstance = GetModuleHandleA(0);
5309     cls.lpszClassName = "wmime_keydown_class";
5310     if (!RegisterClassA(&cls)) assert(0);
5311 }
5312
5313 static void test_wmime_keydown_message(void)
5314 {
5315     HWND hwnd;
5316     MSG msg;
5317
5318     trace("Message sequences by WM_IME_KEYDOWN\n");
5319
5320     register_wmime_keydown_class();
5321     hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
5322                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5323                            NULL, NULL, 0);
5324     flush_events();
5325     flush_sequence();
5326
5327     SendMessage(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
5328     SendMessage(hwnd, WM_CHAR, 'A', 1);
5329     ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
5330
5331     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
5332     {
5333         TranslateMessage(&msg);
5334         DispatchMessage(&msg);
5335     }
5336     ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
5337
5338     DestroyWindow(hwnd);
5339 }
5340
5341 /************* painting message test ********************/
5342
5343 void dump_region(HRGN hrgn)
5344 {
5345     DWORD i, size;
5346     RGNDATA *data = NULL;
5347     RECT *rect;
5348
5349     if (!hrgn)
5350     {
5351         printf( "null region\n" );
5352         return;
5353     }
5354     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
5355     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
5356     GetRegionData( hrgn, size, data );
5357     printf("%d rects:", data->rdh.nCount );
5358     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
5359         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
5360     printf("\n");
5361     HeapFree( GetProcessHeap(), 0, data );
5362 }
5363
5364 static void check_update_rgn( HWND hwnd, HRGN hrgn )
5365 {
5366     INT ret;
5367     RECT r1, r2;
5368     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
5369     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
5370
5371     ret = GetUpdateRgn( hwnd, update, FALSE );
5372     ok( ret != ERROR, "GetUpdateRgn failed\n" );
5373     if (ret == NULLREGION)
5374     {
5375         ok( !hrgn, "Update region shouldn't be empty\n" );
5376     }
5377     else
5378     {
5379         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
5380         {
5381             ok( 0, "Regions are different\n" );
5382             if (winetest_debug > 0)
5383             {
5384                 printf( "Update region: " );
5385                 dump_region( update );
5386                 printf( "Wanted region: " );
5387                 dump_region( hrgn );
5388             }
5389         }
5390     }
5391     GetRgnBox( update, &r1 );
5392     GetUpdateRect( hwnd, &r2, FALSE );
5393     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
5394         "Rectangles are different: %d,%d-%d,%d / %d,%d-%d,%d\n",
5395         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
5396
5397     DeleteObject( tmp );
5398     DeleteObject( update );
5399 }
5400
5401 static const struct message WmInvalidateRgn[] = {
5402     { WM_NCPAINT, sent },
5403     { WM_GETTEXT, sent|defwinproc|optional },
5404     { 0 }
5405 };
5406
5407 static const struct message WmGetUpdateRect[] = {
5408     { WM_NCPAINT, sent },
5409     { WM_GETTEXT, sent|defwinproc|optional },
5410     { WM_PAINT, sent },
5411     { 0 }
5412 };
5413
5414 static const struct message WmInvalidateFull[] = {
5415     { WM_NCPAINT, sent|wparam, 1 },
5416     { WM_GETTEXT, sent|defwinproc|optional },
5417     { 0 }
5418 };
5419
5420 static const struct message WmInvalidateErase[] = {
5421     { WM_NCPAINT, sent|wparam, 1 },
5422     { WM_GETTEXT, sent|defwinproc|optional },
5423     { WM_ERASEBKGND, sent },
5424     { 0 }
5425 };
5426
5427 static const struct message WmInvalidatePaint[] = {
5428     { WM_PAINT, sent },
5429     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5430     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5431     { 0 }
5432 };
5433
5434 static const struct message WmInvalidateErasePaint[] = {
5435     { WM_PAINT, sent },
5436     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
5437     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5438     { WM_ERASEBKGND, sent|beginpaint },
5439     { 0 }
5440 };
5441
5442 static const struct message WmInvalidateErasePaint2[] = {
5443     { WM_PAINT, sent },
5444     { WM_NCPAINT, sent|beginpaint },
5445     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5446     { WM_ERASEBKGND, sent|beginpaint },
5447     { 0 }
5448 };
5449
5450 static const struct message WmErase[] = {
5451     { WM_ERASEBKGND, sent },
5452     { 0 }
5453 };
5454
5455 static const struct message WmPaint[] = {
5456     { WM_PAINT, sent },
5457     { 0 }
5458 };
5459
5460 static const struct message WmParentOnlyPaint[] = {
5461     { WM_PAINT, sent|parent },
5462     { 0 }
5463 };
5464
5465 static const struct message WmInvalidateParent[] = {
5466     { WM_NCPAINT, sent|parent },
5467     { WM_GETTEXT, sent|defwinproc|parent|optional },
5468     { WM_ERASEBKGND, sent|parent },
5469     { 0 }
5470 };
5471
5472 static const struct message WmInvalidateParentChild[] = {
5473     { WM_NCPAINT, sent|parent },
5474     { WM_GETTEXT, sent|defwinproc|parent|optional },
5475     { WM_ERASEBKGND, sent|parent },
5476     { WM_NCPAINT, sent },
5477     { WM_GETTEXT, sent|defwinproc|optional },
5478     { WM_ERASEBKGND, sent },
5479     { 0 }
5480 };
5481
5482 static const struct message WmInvalidateParentChild2[] = {
5483     { WM_ERASEBKGND, sent|parent },
5484     { WM_NCPAINT, sent },
5485     { WM_GETTEXT, sent|defwinproc|optional },
5486     { WM_ERASEBKGND, sent },
5487     { 0 }
5488 };
5489
5490 static const struct message WmParentPaint[] = {
5491     { WM_PAINT, sent|parent },
5492     { WM_PAINT, sent },
5493     { 0 }
5494 };
5495
5496 static const struct message WmParentPaintNc[] = {
5497     { WM_PAINT, sent|parent },
5498     { WM_PAINT, sent },
5499     { WM_NCPAINT, sent|beginpaint },
5500     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5501     { WM_ERASEBKGND, sent|beginpaint },
5502     { 0 }
5503 };
5504
5505 static const struct message WmChildPaintNc[] = {
5506     { WM_PAINT, sent },
5507     { WM_NCPAINT, sent|beginpaint },
5508     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5509     { WM_ERASEBKGND, sent|beginpaint },
5510     { 0 }
5511 };
5512
5513 static const struct message WmParentErasePaint[] = {
5514     { WM_PAINT, sent|parent },
5515     { WM_NCPAINT, sent|parent|beginpaint },
5516     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5517     { WM_ERASEBKGND, sent|parent|beginpaint },
5518     { WM_PAINT, sent },
5519     { WM_NCPAINT, sent|beginpaint },
5520     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
5521     { WM_ERASEBKGND, sent|beginpaint },
5522     { 0 }
5523 };
5524
5525 static const struct message WmParentOnlyNcPaint[] = {
5526     { WM_PAINT, sent|parent },
5527     { WM_NCPAINT, sent|parent|beginpaint },
5528     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
5529     { 0 }
5530 };
5531
5532 static const struct message WmSetParentStyle[] = {
5533     { WM_STYLECHANGING, sent|parent },
5534     { WM_STYLECHANGED, sent|parent },
5535     { 0 }
5536 };
5537
5538 static void test_paint_messages(void)
5539 {
5540     BOOL ret;
5541     RECT rect;
5542     POINT pt;
5543     MSG msg;
5544     HWND hparent, hchild;
5545     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
5546     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
5547     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5548                                 100, 100, 200, 200, 0, 0, 0, NULL);
5549     ok (hwnd != 0, "Failed to create overlapped window\n");
5550
5551     ShowWindow( hwnd, SW_SHOW );
5552     UpdateWindow( hwnd );
5553     flush_events();
5554     flush_sequence();
5555
5556     check_update_rgn( hwnd, 0 );
5557     SetRectRgn( hrgn, 10, 10, 20, 20 );
5558     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5559     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5560     check_update_rgn( hwnd, hrgn );
5561     SetRectRgn( hrgn2, 20, 20, 30, 30 );
5562     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
5563     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5564     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
5565     check_update_rgn( hwnd, hrgn );
5566     /* validate everything */
5567     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5568     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5569     check_update_rgn( hwnd, 0 );
5570
5571     /* test empty region */
5572     SetRectRgn( hrgn, 10, 10, 10, 15 );
5573     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5574     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5575     check_update_rgn( hwnd, 0 );
5576     /* test empty rect */
5577     SetRect( &rect, 10, 10, 10, 15 );
5578     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
5579     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
5580     check_update_rgn( hwnd, 0 );
5581
5582     /* flush pending messages */
5583     flush_events();
5584     flush_sequence();
5585
5586     GetClientRect( hwnd, &rect );
5587     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
5588     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
5589      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5590      */
5591     trace("testing InvalidateRect(0, NULL, FALSE)\n");
5592     SetRectEmpty( &rect );
5593     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
5594     check_update_rgn( hwnd, hrgn );
5595     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5596     flush_events();
5597     ok_sequence( WmPaint, "Paint", FALSE );
5598     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5599     check_update_rgn( hwnd, 0 );
5600
5601     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
5602      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
5603      */
5604     trace("testing ValidateRect(0, NULL)\n");
5605     SetRectEmpty( &rect );
5606     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
5607     check_update_rgn( hwnd, hrgn );
5608     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5609     flush_events();
5610     ok_sequence( WmPaint, "Paint", FALSE );
5611     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
5612     check_update_rgn( hwnd, 0 );
5613
5614     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
5615     SetLastError(0xdeadbeef);
5616     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
5617     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
5618        "wrong error code %d\n", GetLastError());
5619     check_update_rgn( hwnd, 0 );
5620     flush_events();
5621     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5622
5623     trace("testing ValidateRgn(0, NULL)\n");
5624     SetLastError(0xdeadbeef);
5625     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
5626     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
5627        broken( GetLastError() == 0xdeadbeef ) /* win9x */,
5628        "wrong error code %d\n", GetLastError());
5629     check_update_rgn( hwnd, 0 );
5630     flush_events();
5631     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
5632
5633     /* now with frame */
5634     SetRectRgn( hrgn, -5, -5, 20, 20 );
5635
5636     /* flush pending messages */
5637     flush_events();
5638     flush_sequence();
5639     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5640     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5641
5642     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
5643     check_update_rgn( hwnd, hrgn );
5644
5645     flush_sequence();
5646     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5647     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5648
5649     flush_sequence();
5650     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
5651     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
5652
5653     GetClientRect( hwnd, &rect );
5654     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
5655     check_update_rgn( hwnd, hrgn );
5656
5657     flush_sequence();
5658     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
5659     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
5660
5661     flush_sequence();
5662     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
5663     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
5664     check_update_rgn( hwnd, 0 );
5665
5666     flush_sequence();
5667     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
5668     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
5669     check_update_rgn( hwnd, 0 );
5670
5671     flush_sequence();
5672     SetRectRgn( hrgn, 0, 0, 100, 100 );
5673     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
5674     SetRectRgn( hrgn, 0, 0, 50, 100 );
5675     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
5676     SetRectRgn( hrgn, 50, 0, 100, 100 );
5677     check_update_rgn( hwnd, hrgn );
5678     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5679     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
5680     check_update_rgn( hwnd, 0 );
5681
5682     flush_sequence();
5683     SetRectRgn( hrgn, 0, 0, 100, 100 );
5684     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5685     SetRectRgn( hrgn, 0, 0, 100, 50 );
5686     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
5687     ok_sequence( WmErase, "Erase", FALSE );
5688     SetRectRgn( hrgn, 0, 50, 100, 100 );
5689     check_update_rgn( hwnd, hrgn );
5690
5691     flush_sequence();
5692     SetRectRgn( hrgn, 0, 0, 100, 100 );
5693     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
5694     SetRectRgn( hrgn, 0, 0, 50, 50 );
5695     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
5696     ok_sequence( WmPaint, "Paint", FALSE );
5697
5698     flush_sequence();
5699     SetRectRgn( hrgn, -4, -4, -2, -2 );
5700     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5701     SetRectRgn( hrgn, -200, -200, -198, -198 );
5702     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
5703     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
5704
5705     flush_sequence();
5706     SetRectRgn( hrgn, -4, -4, -2, -2 );
5707     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5708     SetRectRgn( hrgn, -4, -4, -3, -3 );
5709     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
5710     SetRectRgn( hrgn, 0, 0, 1, 1 );
5711     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
5712     ok_sequence( WmPaint, "Paint", FALSE );
5713
5714     flush_sequence();
5715     SetRectRgn( hrgn, -4, -4, -1, -1 );
5716     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5717     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
5718     /* make sure no WM_PAINT was generated */
5719     flush_events();
5720     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
5721
5722     flush_sequence();
5723     SetRectRgn( hrgn, -4, -4, -1, -1 );
5724     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
5725     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
5726     {
5727         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
5728         {
5729             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
5730             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
5731             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
5732             ret = GetUpdateRect( hwnd, &rect, FALSE );
5733             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
5734             /* this will send WM_NCPAINT and validate the non client area */
5735             ret = GetUpdateRect( hwnd, &rect, TRUE );
5736             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
5737         }
5738         DispatchMessage( &msg );
5739     }
5740     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
5741
5742     DestroyWindow( hwnd );
5743
5744     /* now test with a child window */
5745
5746     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5747                               100, 100, 200, 200, 0, 0, 0, NULL);
5748     ok (hparent != 0, "Failed to create parent window\n");
5749
5750     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
5751                            10, 10, 100, 100, hparent, 0, 0, NULL);
5752     ok (hchild != 0, "Failed to create child window\n");
5753
5754     ShowWindow( hparent, SW_SHOW );
5755     UpdateWindow( hparent );
5756     UpdateWindow( hchild );
5757     flush_events();
5758     flush_sequence();
5759     log_all_parent_messages++;
5760
5761     SetRect( &rect, 0, 0, 50, 50 );
5762     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5763     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5764     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
5765
5766     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5767     pt.x = pt.y = 0;
5768     MapWindowPoints( hchild, hparent, &pt, 1 );
5769     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
5770     check_update_rgn( hchild, hrgn );
5771     SetRectRgn( hrgn, 0, 0, 50, 50 );
5772     check_update_rgn( hparent, hrgn );
5773     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5774     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
5775     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5776     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5777
5778     flush_events();
5779     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
5780
5781     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5782     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5783     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
5784     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
5785     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
5786
5787     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
5788     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
5789     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
5790
5791     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5792     flush_sequence();
5793     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5794     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5795     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
5796
5797     /* flush all paint messages */
5798     flush_events();
5799     flush_sequence();
5800
5801     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
5802     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
5803     SetRectRgn( hrgn, 0, 0, 50, 50 );
5804     check_update_rgn( hparent, hrgn );
5805     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5806     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5807     SetRectRgn( hrgn, 0, 0, 50, 50 );
5808     check_update_rgn( hparent, hrgn );
5809
5810     /* flush all paint messages */
5811     flush_events();
5812     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5813     flush_sequence();
5814
5815     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
5816     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5817     SetRectRgn( hrgn, 0, 0, 50, 50 );
5818     check_update_rgn( hparent, hrgn );
5819     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5820     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5821     SetRectRgn( hrgn2, 10, 10, 50, 50 );
5822     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
5823     check_update_rgn( hparent, hrgn );
5824     /* flush all paint messages */
5825     flush_events();
5826     flush_sequence();
5827
5828     /* same as above but parent gets completely validated */
5829     SetRect( &rect, 20, 20, 30, 30 );
5830     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5831     SetRectRgn( hrgn, 20, 20, 30, 30 );
5832     check_update_rgn( hparent, hrgn );
5833     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
5834     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5835     check_update_rgn( hparent, 0 );  /* no update region */
5836     flush_events();
5837     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
5838
5839     /* make sure RDW_VALIDATE on child doesn't have the same effect */
5840     flush_sequence();
5841     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5842     SetRectRgn( hrgn, 20, 20, 30, 30 );
5843     check_update_rgn( hparent, hrgn );
5844     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
5845     SetRectRgn( hrgn, 20, 20, 30, 30 );
5846     check_update_rgn( hparent, hrgn );
5847
5848     /* same as above but normal WM_PAINT doesn't validate parent */
5849     flush_sequence();
5850     SetRect( &rect, 20, 20, 30, 30 );
5851     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5852     SetRectRgn( hrgn, 20, 20, 30, 30 );
5853     check_update_rgn( hparent, hrgn );
5854     /* no WM_PAINT in child while parent still pending */
5855     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5856     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5857     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5858     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
5859
5860     flush_sequence();
5861     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5862     /* no WM_PAINT in child while parent still pending */
5863     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5864     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5865     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
5866     /* now that parent is valid child should get WM_PAINT */
5867     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5868     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
5869     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5870     ok_sequence( WmEmptySeq, "No other message", FALSE );
5871
5872     /* same thing with WS_CLIPCHILDREN in parent */
5873     flush_sequence();
5874     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
5875     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5876     /* changing style invalidates non client area, but we need to invalidate something else to see it */
5877     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
5878     ok_sequence( WmEmptySeq, "No message", FALSE );
5879     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
5880     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
5881
5882     flush_sequence();
5883     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
5884     SetRectRgn( hrgn, 20, 20, 30, 30 );
5885     check_update_rgn( hparent, hrgn );
5886     /* no WM_PAINT in child while parent still pending */
5887     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5888     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
5889     /* WM_PAINT in parent first */
5890     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
5891     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
5892
5893     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
5894     flush_sequence();
5895     SetRect( &rect, 0, 0, 30, 30 );
5896     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
5897     SetRectRgn( hrgn, 0, 0, 30, 30 );
5898     check_update_rgn( hparent, hrgn );
5899     flush_events();
5900     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
5901
5902     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5903     flush_sequence();
5904     SetRect( &rect, -10, 0, 30, 30 );
5905     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5906     SetRect( &rect, 0, 0, 20, 20 );
5907     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5908     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5909     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
5910
5911     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
5912     flush_sequence();
5913     SetRect( &rect, -10, 0, 30, 30 );
5914     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
5915     SetRect( &rect, 0, 0, 100, 100 );
5916     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
5917     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
5918     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
5919     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
5920     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
5921
5922     /* test RDW_INTERNALPAINT behavior */
5923
5924     flush_sequence();
5925     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
5926     flush_events();
5927     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5928
5929     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
5930     flush_events();
5931     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5932
5933     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5934     flush_events();
5935     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
5936
5937     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
5938     UpdateWindow( hparent );
5939     flush_events();
5940     flush_sequence();
5941     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
5942     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5943     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5944                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5945     flush_events();
5946     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
5947
5948     UpdateWindow( hparent );
5949     flush_events();
5950     flush_sequence();
5951     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
5952     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5953     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5954                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5955     flush_events();
5956     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5957
5958     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
5959     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
5960     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
5961     flush_events();
5962     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
5963
5964     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
5965     UpdateWindow( hparent );
5966     flush_events();
5967     flush_sequence();
5968     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
5969     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5970     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
5971                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5972     flush_events();
5973     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
5974
5975     UpdateWindow( hparent );
5976     flush_events();
5977     flush_sequence();
5978     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
5979     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
5980     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
5981                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
5982     flush_events();
5983     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
5984
5985     ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
5986     ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
5987
5988     UpdateWindow( hparent );
5989     flush_events();
5990     flush_sequence();
5991     trace("testing SetWindowPos(-10000, -10000) on child\n");
5992     SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
5993     check_update_rgn( hchild, 0 );
5994     flush_events();
5995
5996 #if 0 /* this one doesn't pass under Wine yet */
5997     UpdateWindow( hparent );
5998     flush_events();
5999     flush_sequence();
6000     trace("testing ShowWindow(SW_MINIMIZE) on child\n");
6001     ShowWindow( hchild, SW_MINIMIZE );
6002     check_update_rgn( hchild, 0 );
6003     flush_events();
6004 #endif
6005
6006     UpdateWindow( hparent );
6007     flush_events();
6008     flush_sequence();
6009     trace("testing SetWindowPos(-10000, -10000) on parent\n");
6010     SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
6011     check_update_rgn( hparent, 0 );
6012     flush_events();
6013
6014     log_all_parent_messages--;
6015     DestroyWindow( hparent );
6016     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6017
6018     /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
6019
6020     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
6021                               100, 100, 200, 200, 0, 0, 0, NULL);
6022     ok (hparent != 0, "Failed to create parent window\n");
6023
6024     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
6025                            10, 10, 100, 100, hparent, 0, 0, NULL);
6026     ok (hchild != 0, "Failed to create child window\n");
6027
6028     ShowWindow( hparent, SW_SHOW );
6029     UpdateWindow( hparent );
6030     UpdateWindow( hchild );
6031     flush_events();
6032     flush_sequence();
6033
6034     /* moving child outside of parent boundaries changes update region */
6035     SetRect( &rect, 0, 0, 40, 40 );
6036     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6037     SetRectRgn( hrgn, 0, 0, 40, 40 );
6038     check_update_rgn( hchild, hrgn );
6039     MoveWindow( hchild, -10, 10, 100, 100, FALSE );
6040     SetRectRgn( hrgn, 10, 0, 40, 40 );
6041     check_update_rgn( hchild, hrgn );
6042     MoveWindow( hchild, -10, -10, 100, 100, FALSE );
6043     SetRectRgn( hrgn, 10, 10, 40, 40 );
6044     check_update_rgn( hchild, hrgn );
6045
6046     /* moving parent off-screen does too */
6047     SetRect( &rect, 0, 0, 100, 100 );
6048     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
6049     SetRectRgn( hrgn, 0, 0, 100, 100 );
6050     check_update_rgn( hparent, hrgn );
6051     SetRectRgn( hrgn, 10, 10, 40, 40 );
6052     check_update_rgn( hchild, hrgn );
6053     MoveWindow( hparent, -20, -20, 200, 200, FALSE );
6054     SetRectRgn( hrgn, 20, 20, 100, 100 );
6055     check_update_rgn( hparent, hrgn );
6056     SetRectRgn( hrgn, 30, 30, 40, 40 );
6057     check_update_rgn( hchild, hrgn );
6058
6059     /* invalidated region is cropped by the parent rects */
6060     SetRect( &rect, 0, 0, 50, 50 );
6061     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
6062     SetRectRgn( hrgn, 30, 30, 50, 50 );
6063     check_update_rgn( hchild, hrgn );
6064
6065     DestroyWindow( hparent );
6066     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
6067     flush_sequence();
6068
6069     DeleteObject( hrgn );
6070     DeleteObject( hrgn2 );
6071 }
6072
6073 struct wnd_event
6074 {
6075     HWND hwnd;
6076     HANDLE event;
6077 };
6078
6079 static DWORD WINAPI thread_proc(void *param)
6080 {
6081     MSG msg;
6082     struct wnd_event *wnd_event = (struct wnd_event *)param;
6083
6084     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
6085                                       100, 100, 200, 200, 0, 0, 0, NULL);
6086     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
6087
6088     SetEvent(wnd_event->event);
6089
6090     while (GetMessage(&msg, 0, 0, 0))
6091     {
6092         TranslateMessage(&msg);
6093         DispatchMessage(&msg);
6094     }
6095
6096     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
6097
6098     return 0;
6099 }
6100
6101 static void test_interthread_messages(void)
6102 {
6103     HANDLE hThread;
6104     DWORD tid;
6105     WNDPROC proc;
6106     MSG msg;
6107     char buf[256];
6108     int len, expected_len;
6109     struct wnd_event wnd_event;
6110     BOOL ret;
6111
6112     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
6113     if (!wnd_event.event)
6114     {
6115         trace("skipping interthread message test under win9x\n");
6116         return;
6117     }
6118
6119     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
6120     ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
6121
6122     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6123
6124     CloseHandle(wnd_event.event);
6125
6126     SetLastError(0xdeadbeef);
6127     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
6128     ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
6129        "wrong error code %d\n", GetLastError());
6130
6131     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6132     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
6133
6134     expected_len = lstrlenA("window caption text");
6135     memset(buf, 0, sizeof(buf));
6136     SetLastError(0xdeadbeef);
6137     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
6138     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
6139     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
6140
6141     msg.hwnd = wnd_event.hwnd;
6142     msg.message = WM_GETTEXT;
6143     msg.wParam = sizeof(buf);
6144     msg.lParam = (LPARAM)buf;
6145     memset(buf, 0, sizeof(buf));
6146     SetLastError(0xdeadbeef);
6147     len = DispatchMessageA(&msg);
6148     ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
6149        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
6150
6151     /* the following test causes an exception in user.exe under win9x */
6152     msg.hwnd = wnd_event.hwnd;
6153     msg.message = WM_TIMER;
6154     msg.wParam = 0;
6155     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
6156     SetLastError(0xdeadbeef);
6157     len = DispatchMessageA(&msg);
6158     ok(!len && GetLastError() == 0xdeadbeef,
6159        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
6160
6161     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
6162     ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
6163
6164     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6165     CloseHandle(hThread);
6166
6167     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
6168 }
6169
6170
6171 static const struct message WmVkN[] = {
6172     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6173     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6174     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6175     { WM_CHAR, wparam|lparam, 'n', 1 },
6176     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
6177     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6178     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6179     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6180     { 0 }
6181 };
6182 static const struct message WmShiftVkN[] = {
6183     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6184     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6185     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6186     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6187     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6188     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6189     { WM_CHAR, wparam|lparam, 'N', 1 },
6190     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
6191     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6192     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6193     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6194     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6195     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6196     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6197     { 0 }
6198 };
6199 static const struct message WmCtrlVkN[] = {
6200     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6201     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6202     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6203     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6204     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6205     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
6206     { WM_CHAR, wparam|lparam, 0x000e, 1 },
6207     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6208     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6209     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6210     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6211     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6212     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6213     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6214     { 0 }
6215 };
6216 static const struct message WmCtrlVkN_2[] = {
6217     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6218     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6219     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6220     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6221     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6222     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
6223     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6224     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6225     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6226     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6227     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6228     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6229     { 0 }
6230 };
6231 static const struct message WmAltVkN[] = {
6232     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6233     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6234     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6235     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6236     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6237     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6238     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
6239     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
6240     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
6241     { HCBT_SYSCOMMAND, hook },
6242     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6243     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6244     { 0x00AE, sent|defwinproc|optional }, /* XP */
6245     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
6246     { WM_INITMENU, sent|defwinproc },
6247     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6248     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
6249     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6250     { WM_CAPTURECHANGED, sent|defwinproc },
6251     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
6252     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6253     { WM_EXITMENULOOP, sent|defwinproc },
6254     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
6255     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
6256     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6257     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6258     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6259     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6260     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6261     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6262     { 0 }
6263 };
6264 static const struct message WmAltVkN_2[] = {
6265     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6266     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6267     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6268     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6269     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
6270     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
6271     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6272     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
6273     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6274     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6275     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6276     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6277     { 0 }
6278 };
6279 static const struct message WmCtrlAltVkN[] = {
6280     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6281     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6282     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6283     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6284     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6285     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6286     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6287     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6288     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
6289     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6290     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6291     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6292     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6293     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6294     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6295     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6296     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6297     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6298     { 0 }
6299 };
6300 static const struct message WmCtrlShiftVkN[] = {
6301     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6302     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6303     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6304     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
6305     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
6306     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
6307     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
6308     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
6309     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
6310     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
6311     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
6312     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6313     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
6314     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
6315     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
6316     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6317     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6318     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6319     { 0 }
6320 };
6321 static const struct message WmCtrlAltShiftVkN[] = {
6322     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
6323     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
6324     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
6325     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6326     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6327     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6328     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
6329     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
6330     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
6331     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
6332     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
6333     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
6334     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
6335     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
6336     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
6337     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
6338     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
6339     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
6340     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6341     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6342     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6343     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
6344     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
6345     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
6346     { 0 }
6347 };
6348 static const struct message WmAltPressRelease[] = {
6349     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6350     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6351     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6352     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6353     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6354     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6355     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
6356     { HCBT_SYSCOMMAND, hook },
6357     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
6358     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6359     { WM_INITMENU, sent|defwinproc },
6360     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6361     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
6362     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
6363
6364     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
6365
6366     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6367     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
6368     { WM_CAPTURECHANGED, sent|defwinproc },
6369     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
6370     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
6371     { WM_EXITMENULOOP, sent|defwinproc },
6372     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6373     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6374     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6375     { 0 }
6376 };
6377 static const struct message WmAltMouseButton[] = {
6378     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
6379     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
6380     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
6381     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
6382     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
6383     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
6384     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
6385     { WM_LBUTTONUP, wparam, 0, 0 },
6386     { WM_LBUTTONUP, sent|wparam, 0, 0 },
6387     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
6388     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
6389     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
6390     { 0 }
6391 };
6392 static const struct message WmF1Seq[] = {
6393     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
6394     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
6395     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
6396     { WM_KEYF1, wparam|lparam, 0, 0 },
6397     { WM_KEYF1, sent|wparam|lparam, 0, 0 },
6398     { WM_HELP, sent|defwinproc },
6399     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
6400     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
6401     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
6402     { 0 }
6403 };
6404 static const struct message WmVkAppsSeq[] = {
6405     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
6406     { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
6407     { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
6408     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
6409     { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
6410     { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
6411     { WM_CONTEXTMENU, lparam, /*hwnd*/0, (LPARAM)-1 },
6412     { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 },
6413     { 0 }
6414 };
6415
6416 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
6417 {
6418     MSG msg;
6419
6420     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
6421     {
6422         struct message log_msg;
6423
6424         trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
6425
6426         /* ignore some unwanted messages */
6427         if (msg.message == WM_MOUSEMOVE ||
6428             msg.message == WM_GETICON ||
6429             msg.message == WM_TIMER ||
6430             msg.message == WM_DEVICECHANGE)
6431             continue;
6432
6433         log_msg.message = msg.message;
6434         log_msg.flags = wparam|lparam;
6435         log_msg.wParam = msg.wParam;
6436         log_msg.lParam = msg.lParam;
6437         add_message(&log_msg);
6438
6439         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
6440         {
6441             TranslateMessage(&msg);
6442             DispatchMessage(&msg);
6443         }
6444     }
6445 }
6446
6447 static void test_accelerators(void)
6448 {
6449     RECT rc;
6450     SHORT state;
6451     HACCEL hAccel;
6452     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6453                                 100, 100, 200, 200, 0, 0, 0, NULL);
6454     BOOL ret;
6455
6456     assert(hwnd != 0);
6457     UpdateWindow(hwnd);
6458     flush_events();
6459     flush_sequence();
6460
6461     SetFocus(hwnd);
6462     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
6463
6464     state = GetKeyState(VK_SHIFT);
6465     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
6466     state = GetKeyState(VK_CAPITAL);
6467     ok(state == 0, "wrong CapsLock state %04x\n", state);
6468
6469     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
6470     assert(hAccel != 0);
6471
6472     flush_events();
6473     pump_msg_loop(hwnd, 0);
6474     flush_sequence();
6475
6476     trace("testing VK_N press/release\n");
6477     flush_sequence();
6478     keybd_event('N', 0, 0, 0);
6479     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6480     pump_msg_loop(hwnd, hAccel);
6481     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6482
6483     trace("testing Shift+VK_N press/release\n");
6484     flush_sequence();
6485     keybd_event(VK_SHIFT, 0, 0, 0);
6486     keybd_event('N', 0, 0, 0);
6487     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6488     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6489     pump_msg_loop(hwnd, hAccel);
6490     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6491
6492     trace("testing Ctrl+VK_N press/release\n");
6493     flush_sequence();
6494     keybd_event(VK_CONTROL, 0, 0, 0);
6495     keybd_event('N', 0, 0, 0);
6496     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6497     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6498     pump_msg_loop(hwnd, hAccel);
6499     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
6500
6501     trace("testing Alt+VK_N press/release\n");
6502     flush_sequence();
6503     keybd_event(VK_MENU, 0, 0, 0);
6504     keybd_event('N', 0, 0, 0);
6505     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6506     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6507     pump_msg_loop(hwnd, hAccel);
6508     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
6509
6510     trace("testing Ctrl+Alt+VK_N press/release 1\n");
6511     flush_sequence();
6512     keybd_event(VK_CONTROL, 0, 0, 0);
6513     keybd_event(VK_MENU, 0, 0, 0);
6514     keybd_event('N', 0, 0, 0);
6515     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6516     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6517     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6518     pump_msg_loop(hwnd, hAccel);
6519     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
6520
6521     ret = DestroyAcceleratorTable(hAccel);
6522     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6523
6524     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
6525     assert(hAccel != 0);
6526
6527     trace("testing VK_N press/release\n");
6528     flush_sequence();
6529     keybd_event('N', 0, 0, 0);
6530     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6531     pump_msg_loop(hwnd, hAccel);
6532     ok_sequence(WmVkN, "VK_N press/release", FALSE);
6533
6534     trace("testing Shift+VK_N press/release\n");
6535     flush_sequence();
6536     keybd_event(VK_SHIFT, 0, 0, 0);
6537     keybd_event('N', 0, 0, 0);
6538     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6539     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6540     pump_msg_loop(hwnd, hAccel);
6541     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
6542
6543     trace("testing Ctrl+VK_N press/release 2\n");
6544     flush_sequence();
6545     keybd_event(VK_CONTROL, 0, 0, 0);
6546     keybd_event('N', 0, 0, 0);
6547     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6548     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6549     pump_msg_loop(hwnd, hAccel);
6550     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
6551
6552     trace("testing Alt+VK_N press/release 2\n");
6553     flush_sequence();
6554     keybd_event(VK_MENU, 0, 0, 0);
6555     keybd_event('N', 0, 0, 0);
6556     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6557     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6558     pump_msg_loop(hwnd, hAccel);
6559     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
6560
6561     trace("testing Ctrl+Alt+VK_N press/release 2\n");
6562     flush_sequence();
6563     keybd_event(VK_CONTROL, 0, 0, 0);
6564     keybd_event(VK_MENU, 0, 0, 0);
6565     keybd_event('N', 0, 0, 0);
6566     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6567     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6568     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6569     pump_msg_loop(hwnd, hAccel);
6570     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
6571
6572     trace("testing Ctrl+Shift+VK_N press/release\n");
6573     flush_sequence();
6574     keybd_event(VK_CONTROL, 0, 0, 0);
6575     keybd_event(VK_SHIFT, 0, 0, 0);
6576     keybd_event('N', 0, 0, 0);
6577     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6578     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6579     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6580     pump_msg_loop(hwnd, hAccel);
6581     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
6582
6583     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
6584     flush_sequence();
6585     keybd_event(VK_CONTROL, 0, 0, 0);
6586     keybd_event(VK_MENU, 0, 0, 0);
6587     keybd_event(VK_SHIFT, 0, 0, 0);
6588     keybd_event('N', 0, 0, 0);
6589     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6590     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
6591     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6592     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
6593     pump_msg_loop(hwnd, hAccel);
6594     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
6595
6596     ret = DestroyAcceleratorTable(hAccel);
6597     ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
6598
6599     trace("testing Alt press/release\n");
6600     flush_sequence();
6601     keybd_event(VK_MENU, 0, 0, 0);
6602     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6603     keybd_event(VK_MENU, 0, 0, 0);
6604     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6605     pump_msg_loop(hwnd, 0);
6606     /* this test doesn't pass in Wine for managed windows */
6607     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
6608
6609     trace("testing Alt+MouseButton press/release\n");
6610     /* first, move mouse pointer inside of the window client area */
6611     GetClientRect(hwnd, &rc);
6612     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
6613     rc.left += (rc.right - rc.left)/2;
6614     rc.top += (rc.bottom - rc.top)/2;
6615     SetCursorPos(rc.left, rc.top);
6616
6617     flush_events();
6618     flush_sequence();
6619     keybd_event(VK_MENU, 0, 0, 0);
6620     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6621     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6622     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
6623     pump_msg_loop(hwnd, 0);
6624     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
6625
6626     trace("testing VK_F1 press/release\n");
6627     keybd_event(VK_F1, 0, 0, 0);
6628     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
6629     pump_msg_loop(hwnd, 0);
6630     ok_sequence(WmF1Seq, "F1 press/release", FALSE);
6631
6632     trace("testing VK_APPS press/release\n");
6633     keybd_event(VK_APPS, 0, 0, 0);
6634     keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
6635     pump_msg_loop(hwnd, 0);
6636     ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
6637
6638     DestroyWindow(hwnd);
6639 }
6640
6641 /************* window procedures ********************/
6642
6643 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
6644                              WPARAM wParam, LPARAM lParam)
6645 {
6646     static long defwndproc_counter = 0;
6647     static long beginpaint_counter = 0;
6648     LRESULT ret;
6649     struct message msg;
6650
6651     trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6652
6653     /* explicitly ignore WM_GETICON message */
6654     if (message == WM_GETICON) return 0;
6655
6656     /* ignore registered messages */
6657     if (message >= 0xc000) return 0;
6658
6659     switch (message)
6660     {
6661         case WM_ENABLE:
6662         {
6663             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
6664             ok((BOOL)wParam == !(style & WS_DISABLED),
6665                 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
6666             break;
6667         }
6668
6669         case WM_CAPTURECHANGED:
6670             if (test_DestroyWindow_flag)
6671             {
6672                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6673                 if (style & WS_CHILD)
6674                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6675                 else if (style & WS_POPUP)
6676                     lParam = WND_POPUP_ID;
6677                 else
6678                     lParam = WND_PARENT_ID;
6679             }
6680             break;
6681
6682         case WM_NCDESTROY:
6683         {
6684             HWND capture;
6685
6686             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
6687             capture = GetCapture();
6688             if (capture)
6689             {
6690                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
6691                 trace("current capture %p, releasing...\n", capture);
6692                 ReleaseCapture();
6693             }
6694         }
6695         /* fall through */
6696         case WM_DESTROY:
6697             if (pGetAncestor)
6698                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
6699             if (test_DestroyWindow_flag)
6700             {
6701                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
6702                 if (style & WS_CHILD)
6703                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
6704                 else if (style & WS_POPUP)
6705                     lParam = WND_POPUP_ID;
6706                 else
6707                     lParam = WND_PARENT_ID;
6708             }
6709             break;
6710
6711         /* test_accelerators() depends on this */
6712         case WM_NCHITTEST:
6713             return HTCLIENT;
6714     
6715         /* ignore */
6716         case WM_MOUSEMOVE:
6717         case WM_SETCURSOR:
6718         case WM_DEVICECHANGE:
6719             return 0;
6720
6721         case WM_WINDOWPOSCHANGING:
6722         case WM_WINDOWPOSCHANGED:
6723         {
6724             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6725
6726             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6727             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6728                   winpos->hwnd, winpos->hwndInsertAfter,
6729                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6730             dump_winpos_flags(winpos->flags);
6731
6732             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6733              * in the high word for internal purposes
6734              */
6735             wParam = winpos->flags & 0xffff;
6736             /* We are not interested in the flags that don't match under XP and Win9x */
6737             wParam &= ~(SWP_NOZORDER);
6738             break;
6739         }
6740     }
6741
6742     msg.message = message;
6743     msg.flags = sent|wparam|lparam;
6744     if (defwndproc_counter) msg.flags |= defwinproc;
6745     if (beginpaint_counter) msg.flags |= beginpaint;
6746     msg.wParam = wParam;
6747     msg.lParam = lParam;
6748     add_message(&msg);
6749
6750     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
6751     {
6752         HWND parent = GetParent(hwnd);
6753         RECT rc;
6754         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
6755
6756         GetClientRect(parent, &rc);
6757         trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
6758         trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
6759               minmax->ptReserved.x, minmax->ptReserved.y,
6760               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
6761               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
6762               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
6763               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
6764
6765         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
6766            minmax->ptMaxSize.x, rc.right);
6767         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
6768            minmax->ptMaxSize.y, rc.bottom);
6769     }
6770
6771     if (message == WM_PAINT)
6772     {
6773         PAINTSTRUCT ps;
6774         beginpaint_counter++;
6775         BeginPaint( hwnd, &ps );
6776         beginpaint_counter--;
6777         EndPaint( hwnd, &ps );
6778         return 0;
6779     }
6780
6781     defwndproc_counter++;
6782     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
6783                   : DefWindowProcA(hwnd, message, wParam, lParam);
6784     defwndproc_counter--;
6785
6786     return ret;
6787 }
6788
6789 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6790 {
6791     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
6792 }
6793
6794 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6795 {
6796     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
6797 }
6798
6799 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6800 {
6801     static long defwndproc_counter = 0;
6802     LRESULT ret;
6803     struct message msg;
6804
6805     trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6806
6807     switch (message)
6808     {
6809     case WM_GETICON:
6810         /* explicitly ignore WM_GETICON message */
6811         return 0;
6812     case WM_QUERYENDSESSION:
6813     case WM_ENDSESSION:
6814         lParam &= ~0x01;  /* Vista adds a 0x01 flag */
6815         break;
6816     }
6817
6818     msg.message = message;
6819     msg.flags = sent|wparam|lparam;
6820     if (defwndproc_counter) msg.flags |= defwinproc;
6821     msg.wParam = wParam;
6822     msg.lParam = lParam;
6823     add_message(&msg);
6824
6825     if (message == WM_CREATE)
6826     {
6827         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
6828         SetWindowLongA(hwnd, GWL_STYLE, style);
6829     }
6830
6831     defwndproc_counter++;
6832     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6833     defwndproc_counter--;
6834
6835     return ret;
6836 }
6837
6838 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6839 {
6840     static long defwndproc_counter = 0;
6841     static long beginpaint_counter = 0;
6842     LRESULT ret;
6843     struct message msg;
6844     LPARAM logged_lParam;
6845
6846     trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6847
6848     /* explicitly ignore WM_GETICON message */
6849     if (message == WM_GETICON) return 0;
6850
6851     /* ignore registered messages */
6852     if (message >= 0xc000) return 0;
6853
6854     logged_lParam=lParam;
6855     if (log_all_parent_messages ||
6856         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
6857         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
6858         message == WM_ENABLE || message == WM_ENTERIDLE ||
6859         message == WM_DRAWITEM ||
6860         message == WM_IME_SETCONTEXT)
6861     {
6862         switch (message)
6863         {
6864             /* ignore */
6865             case WM_NCHITTEST:
6866                 return HTCLIENT;
6867             case WM_SETCURSOR:
6868             case WM_MOUSEMOVE:
6869                 return 0;
6870
6871             case WM_ERASEBKGND:
6872             {
6873                 RECT rc;
6874                 INT ret = GetClipBox((HDC)wParam, &rc);
6875
6876                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%d,%d-%d,%d)\n",
6877                        ret, rc.left, rc.top, rc.right, rc.bottom);
6878                 break;
6879             }
6880
6881             case WM_WINDOWPOSCHANGING:
6882             case WM_WINDOWPOSCHANGED:
6883             {
6884                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6885
6886                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6887                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6888                       winpos->hwnd, winpos->hwndInsertAfter,
6889                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6890                 dump_winpos_flags(winpos->flags);
6891
6892                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
6893                  * in the high word for internal purposes
6894                  */
6895                 wParam = winpos->flags & 0xffff;
6896                 /* We are not interested in the flags that don't match under XP and Win9x */
6897                 wParam &= ~(SWP_NOZORDER);
6898                 break;
6899             }
6900
6901             case WM_DRAWITEM:
6902             {
6903                 /* encode DRAWITEMSTRUCT into an LPARAM */
6904                 DRAW_ITEM_STRUCT di;
6905                 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
6906
6907                 trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n",
6908                       dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState);
6909
6910                 di.u.item.type = dis->CtlType;
6911                 di.u.item.ctl_id = dis->CtlID;
6912                 di.u.item.item_id = dis->itemID;
6913                 di.u.item.action = dis->itemAction;
6914                 di.u.item.state = dis->itemState;
6915
6916                 logged_lParam = di.u.lp;
6917                 break;
6918             }
6919         }
6920
6921         msg.message = message;
6922         msg.flags = sent|parent|wparam|lparam;
6923         if (defwndproc_counter) msg.flags |= defwinproc;
6924         if (beginpaint_counter) msg.flags |= beginpaint;
6925         msg.wParam = wParam;
6926         msg.lParam = logged_lParam;
6927         add_message(&msg);
6928     }
6929
6930     if (message == WM_PAINT)
6931     {
6932         PAINTSTRUCT ps;
6933         beginpaint_counter++;
6934         BeginPaint( hwnd, &ps );
6935         beginpaint_counter--;
6936         EndPaint( hwnd, &ps );
6937         return 0;
6938     }
6939
6940     defwndproc_counter++;
6941     ret = DefWindowProcA(hwnd, message, wParam, lParam);
6942     defwndproc_counter--;
6943
6944     return ret;
6945 }
6946
6947 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6948 {
6949     static long defwndproc_counter = 0;
6950     LRESULT ret;
6951     struct message msg;
6952
6953     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
6954
6955     /* explicitly ignore WM_GETICON message */
6956     if (message == WM_GETICON) return 0;
6957
6958     /* ignore registered messages */
6959     if (message >= 0xc000) return 0;
6960
6961     if (test_def_id)
6962     {
6963         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
6964         ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
6965         if (after_end_dialog)
6966             ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
6967         else
6968             ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
6969     }
6970
6971     switch (message)
6972     {
6973         case WM_WINDOWPOSCHANGING:
6974         case WM_WINDOWPOSCHANGED:
6975         {
6976             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
6977
6978             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
6979             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
6980                   winpos->hwnd, winpos->hwndInsertAfter,
6981                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
6982             dump_winpos_flags(winpos->flags);
6983
6984             /* Log only documented flags, win2k uses 0x1000 and 0x2000
6985              * in the high word for internal purposes
6986              */
6987             wParam = winpos->flags & 0xffff;
6988             /* We are not interested in the flags that don't match under XP and Win9x */
6989             wParam &= ~(SWP_NOZORDER);
6990             break;
6991         }
6992     }
6993
6994     msg.message = message;
6995     msg.flags = sent|wparam|lparam;
6996     if (defwndproc_counter) msg.flags |= defwinproc;
6997     msg.wParam = wParam;
6998     msg.lParam = lParam;
6999     add_message(&msg);
7000
7001     defwndproc_counter++;
7002     ret = DefDlgProcA(hwnd, message, wParam, lParam);
7003     defwndproc_counter--;
7004
7005     return ret;
7006 }
7007
7008 static void dump_winpos_flags(UINT flags)
7009 {
7010     if (!winetest_debug) return;
7011
7012     if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW");
7013     if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW");
7014     if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE");
7015     if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED");
7016     if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS");
7017     if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER");
7018     if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING");
7019     if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE");
7020     if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS");
7021     if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER");
7022     if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW");
7023     if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE");
7024     if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE");
7025     if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE");
7026     if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE");
7027
7028 #define DUMPED_FLAGS \
7029     (SWP_NOSIZE | \
7030     SWP_NOMOVE | \
7031     SWP_NOZORDER | \
7032     SWP_NOREDRAW | \
7033     SWP_NOACTIVATE | \
7034     SWP_FRAMECHANGED | \
7035     SWP_SHOWWINDOW | \
7036     SWP_HIDEWINDOW | \
7037     SWP_NOCOPYBITS | \
7038     SWP_NOOWNERZORDER | \
7039     SWP_NOSENDCHANGING | \
7040     SWP_DEFERERASE | \
7041     SWP_ASYNCWINDOWPOS | \
7042     SWP_NOCLIENTSIZE | \
7043     SWP_NOCLIENTMOVE)
7044
7045     if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS);
7046     printf("\n");
7047 #undef DUMPED_FLAGS
7048 }
7049
7050 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7051 {
7052     static long defwndproc_counter = 0;
7053     LRESULT ret;
7054     struct message msg;
7055
7056     /* log only specific messages we are interested in */
7057     switch (message)
7058     {
7059 #if 0 /* probably log these as well */
7060     case WM_ACTIVATE:
7061     case WM_SETFOCUS:
7062     case WM_KILLFOCUS:
7063 #endif
7064     case WM_SHOWWINDOW:
7065         trace("WM_SHOWWINDOW %ld\n", wParam);
7066         break;
7067     case WM_SIZE:
7068         trace("WM_SIZE %ld\n", wParam);
7069         break;
7070     case WM_MOVE:
7071         trace("WM_MOVE\n");
7072         break;
7073     case WM_GETMINMAXINFO:
7074         trace("WM_GETMINMAXINFO\n");
7075         break;
7076
7077     case WM_WINDOWPOSCHANGING:
7078     case WM_WINDOWPOSCHANGED:
7079     {
7080         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
7081
7082         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
7083         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
7084               winpos->hwnd, winpos->hwndInsertAfter,
7085               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
7086         trace("flags: ");
7087         dump_winpos_flags(winpos->flags);
7088
7089         /* Log only documented flags, win2k uses 0x1000 and 0x2000
7090          * in the high word for internal purposes
7091          */
7092         wParam = winpos->flags & 0xffff;
7093         /* We are not interested in the flags that don't match under XP and Win9x */
7094         wParam &= ~(SWP_NOZORDER);
7095         break;
7096     }
7097
7098     default: /* ignore */
7099         /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
7100         return DefWindowProcA(hwnd, message, wParam, lParam);
7101     }
7102
7103     msg.message = message;
7104     msg.flags = sent|wparam|lparam;
7105     if (defwndproc_counter) msg.flags |= defwinproc;
7106     msg.wParam = wParam;
7107     msg.lParam = lParam;
7108     add_message(&msg);
7109
7110     defwndproc_counter++;
7111     ret = DefWindowProcA(hwnd, message, wParam, lParam);
7112     defwndproc_counter--;
7113
7114     return ret;
7115 }
7116
7117 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7118 {
7119     switch (msg)
7120     {
7121         case WM_CREATE: return 0;
7122         case WM_PAINT:
7123         {
7124             MSG msg2;
7125             static int i = 0;
7126
7127             if (i < 256)
7128             {
7129                 i++;
7130                 if (PeekMessageA(&msg2, 0, 0, 0, 1))
7131                 {
7132                     TranslateMessage(&msg2);
7133                     DispatchMessage(&msg2);
7134                 }
7135                 i--;
7136             }
7137             else ok(broken(1), "infinite loop\n");
7138             if ( i == 0)
7139                 paint_loop_done = 1;
7140             return DefWindowProcA(hWnd,msg,wParam,lParam);
7141         }
7142     }
7143     return DefWindowProcA(hWnd,msg,wParam,lParam);
7144 }
7145
7146 static BOOL RegisterWindowClasses(void)
7147 {
7148     WNDCLASSA cls;
7149     WNDCLASSW clsW;
7150
7151     cls.style = 0;
7152     cls.lpfnWndProc = MsgCheckProcA;
7153     cls.cbClsExtra = 0;
7154     cls.cbWndExtra = 0;
7155     cls.hInstance = GetModuleHandleA(0);
7156     cls.hIcon = 0;
7157     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
7158     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
7159     cls.lpszMenuName = NULL;
7160     cls.lpszClassName = "TestWindowClass";
7161     if(!RegisterClassA(&cls)) return FALSE;
7162
7163     cls.lpfnWndProc = ShowWindowProcA;
7164     cls.lpszClassName = "ShowWindowClass";
7165     if(!RegisterClassA(&cls)) return FALSE;
7166
7167     cls.lpfnWndProc = PopupMsgCheckProcA;
7168     cls.lpszClassName = "TestPopupClass";
7169     if(!RegisterClassA(&cls)) return FALSE;
7170
7171     cls.lpfnWndProc = ParentMsgCheckProcA;
7172     cls.lpszClassName = "TestParentClass";
7173     if(!RegisterClassA(&cls)) return FALSE;
7174
7175     cls.lpfnWndProc = DefWindowProcA;
7176     cls.lpszClassName = "SimpleWindowClass";
7177     if(!RegisterClassA(&cls)) return FALSE;
7178
7179     cls.lpfnWndProc = PaintLoopProcA;
7180     cls.lpszClassName = "PaintLoopWindowClass";
7181     if(!RegisterClassA(&cls)) return FALSE;
7182
7183     cls.style = CS_NOCLOSE;
7184     cls.lpszClassName = "NoCloseWindowClass";
7185     if(!RegisterClassA(&cls)) return FALSE;
7186
7187     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
7188     cls.style = 0;
7189     cls.hInstance = GetModuleHandleA(0);
7190     cls.hbrBackground = 0;
7191     cls.lpfnWndProc = TestDlgProcA;
7192     cls.lpszClassName = "TestDialogClass";
7193     if(!RegisterClassA(&cls)) return FALSE;
7194
7195     clsW.style = 0;
7196     clsW.lpfnWndProc = MsgCheckProcW;
7197     clsW.cbClsExtra = 0;
7198     clsW.cbWndExtra = 0;
7199     clsW.hInstance = GetModuleHandleW(0);
7200     clsW.hIcon = 0;
7201     clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
7202     clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
7203     clsW.lpszMenuName = NULL;
7204     clsW.lpszClassName = testWindowClassW;
7205     RegisterClassW(&clsW);  /* ignore error, this fails on Win9x */
7206
7207     return TRUE;
7208 }
7209
7210 static BOOL is_our_logged_class(HWND hwnd)
7211 {
7212     char buf[256];
7213
7214     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7215     {
7216         if (!lstrcmpiA(buf, "TestWindowClass") ||
7217             !lstrcmpiA(buf, "ShowWindowClass") ||
7218             !lstrcmpiA(buf, "TestParentClass") ||
7219             !lstrcmpiA(buf, "TestPopupClass") ||
7220             !lstrcmpiA(buf, "SimpleWindowClass") ||
7221             !lstrcmpiA(buf, "TestDialogClass") ||
7222             !lstrcmpiA(buf, "MDI_frame_class") ||
7223             !lstrcmpiA(buf, "MDI_client_class") ||
7224             !lstrcmpiA(buf, "MDI_child_class") ||
7225             !lstrcmpiA(buf, "my_button_class") ||
7226             !lstrcmpiA(buf, "my_edit_class") ||
7227             !lstrcmpiA(buf, "static") ||
7228             !lstrcmpiA(buf, "ListBox") ||
7229             !lstrcmpiA(buf, "ComboBox") ||
7230             !lstrcmpiA(buf, "MyDialogClass") ||
7231             !lstrcmpiA(buf, "#32770") ||
7232             !lstrcmpiA(buf, "#32768"))
7233         return TRUE;
7234         trace("ignoring window class %s\n", buf);
7235     }
7236     return FALSE;
7237 }
7238
7239 static HHOOK hCBT_hook;
7240 static DWORD cbt_hook_thread_id;
7241
7242 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7243
7244     static const char * const CBT_code_name[10] = {
7245         "HCBT_MOVESIZE",
7246         "HCBT_MINMAX",
7247         "HCBT_QS",
7248         "HCBT_CREATEWND",
7249         "HCBT_DESTROYWND",
7250         "HCBT_ACTIVATE",
7251         "HCBT_CLICKSKIPPED",
7252         "HCBT_KEYSKIPPED",
7253         "HCBT_SYSCOMMAND",
7254         "HCBT_SETFOCUS" };
7255     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
7256     HWND hwnd;
7257
7258     trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
7259
7260     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7261
7262     if (nCode == HCBT_CLICKSKIPPED)
7263     {
7264         /* ignore this event, XP sends it a lot when switching focus between windows */
7265         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7266     }
7267
7268     if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
7269     {
7270         struct message msg;
7271
7272         msg.message = nCode;
7273         msg.flags = hook|wparam|lparam;
7274         msg.wParam = wParam;
7275         msg.lParam = lParam;
7276         add_message(&msg);
7277
7278         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7279     }
7280
7281     if (nCode == HCBT_DESTROYWND)
7282     {
7283         if (test_DestroyWindow_flag)
7284         {
7285             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
7286             if (style & WS_CHILD)
7287                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
7288             else if (style & WS_POPUP)
7289                 lParam = WND_POPUP_ID;
7290             else
7291                 lParam = WND_PARENT_ID;
7292         }
7293     }
7294
7295     /* Log also SetFocus(0) calls */
7296     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7297
7298     if (is_our_logged_class(hwnd))
7299     {
7300         struct message msg;
7301
7302         msg.message = nCode;
7303         msg.flags = hook|wparam|lparam;
7304         msg.wParam = wParam;
7305         msg.lParam = lParam;
7306         add_message(&msg);
7307     }
7308     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
7309 }
7310
7311 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
7312                                     DWORD event,
7313                                     HWND hwnd,
7314                                     LONG object_id,
7315                                     LONG child_id,
7316                                     DWORD thread_id,
7317                                     DWORD event_time)
7318 {
7319     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7320            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7321
7322     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
7323
7324     /* ignore mouse cursor events */
7325     if (object_id == OBJID_CURSOR) return;
7326
7327     if (!hwnd || is_our_logged_class(hwnd))
7328     {
7329         struct message msg;
7330
7331         msg.message = event;
7332         msg.flags = winevent_hook|wparam|lparam;
7333         msg.wParam = object_id;
7334         msg.lParam = child_id;
7335         add_message(&msg);
7336     }
7337 }
7338
7339 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
7340 static const WCHAR wszAnsi[] = {'U',0};
7341
7342 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
7343 {
7344     switch (uMsg)
7345     {
7346     case CB_FINDSTRINGEXACT:
7347         trace("String: %p\n", (LPCWSTR)lParam);
7348         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
7349             return 1;
7350         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
7351             return 0;
7352         return -1;
7353     }
7354     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
7355 }
7356
7357 static const struct message WmGetTextLengthAfromW[] = {
7358     { WM_GETTEXTLENGTH, sent },
7359     { WM_GETTEXT, sent|optional },
7360     { 0 }
7361 };
7362
7363 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
7364
7365 /* dummy window proc for WM_GETTEXTLENGTH test */
7366 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
7367 {
7368     switch(msg)
7369     {
7370     case WM_GETTEXTLENGTH:
7371         return lstrlenW(dummy_window_text) + 37;  /* some random length */
7372     case WM_GETTEXT:
7373         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
7374         return lstrlenW( (LPWSTR)lp );
7375     default:
7376         return DefWindowProcW( hwnd, msg, wp, lp );
7377     }
7378 }
7379
7380 static void test_message_conversion(void)
7381 {
7382     static const WCHAR wszMsgConversionClass[] =
7383         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
7384     WNDCLASSW cls;
7385     LRESULT lRes;
7386     HWND hwnd;
7387     WNDPROC wndproc, newproc;
7388     BOOL ret;
7389
7390     cls.style = 0;
7391     cls.lpfnWndProc = MsgConversionProcW;
7392     cls.cbClsExtra = 0;
7393     cls.cbWndExtra = 0;
7394     cls.hInstance = GetModuleHandleW(NULL);
7395     cls.hIcon = NULL;
7396     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
7397     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
7398     cls.lpszMenuName = NULL;
7399     cls.lpszClassName = wszMsgConversionClass;
7400     /* this call will fail on Win9x, but that doesn't matter as this test is
7401      * meaningless on those platforms */
7402     if(!RegisterClassW(&cls)) return;
7403
7404     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
7405                            100, 100, 200, 200, 0, 0, 0, NULL);
7406     ok(hwnd != NULL, "Window creation failed\n");
7407
7408     /* {W, A} -> A */
7409
7410     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
7411     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7412     ok(lRes == 0, "String should have been converted\n");
7413     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7414     ok(lRes == 1, "String shouldn't have been converted\n");
7415
7416     /* {W, A} -> W */
7417
7418     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
7419     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7420     ok(lRes == 1, "String shouldn't have been converted\n");
7421     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7422     ok(lRes == 1, "String shouldn't have been converted\n");
7423
7424     /* Synchronous messages */
7425
7426     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7427     ok(lRes == 0, "String should have been converted\n");
7428     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7429     ok(lRes == 1, "String shouldn't have been converted\n");
7430
7431     /* Asynchronous messages */
7432
7433     SetLastError(0);
7434     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7435     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7436         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7437     SetLastError(0);
7438     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7439     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7440         "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7441     SetLastError(0);
7442     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7443     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7444         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7445     SetLastError(0);
7446     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7447     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7448         "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7449     SetLastError(0);
7450     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7451     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7452         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7453     SetLastError(0);
7454     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
7455     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7456         "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7457     SetLastError(0);
7458     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7459     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7460         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7461     SetLastError(0);
7462     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
7463     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
7464         "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
7465
7466     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
7467
7468     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
7469                           WS_OVERLAPPEDWINDOW,
7470                           100, 100, 200, 200, 0, 0, 0, NULL);
7471     assert(hwnd);
7472     flush_sequence();
7473     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
7474     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7475     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7476         "got bad length %ld\n", lRes );
7477
7478     flush_sequence();
7479     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
7480                             hwnd, WM_GETTEXTLENGTH, 0, 0);
7481     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
7482     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
7483         "got bad length %ld\n", lRes );
7484
7485     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
7486     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
7487     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7488     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7489                                      NULL, 0, NULL, NULL ) ||
7490         broken(lRes == lstrlenW(dummy_window_text) + 37),
7491         "got bad length %ld\n", lRes );
7492
7493     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
7494     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
7495     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
7496                                      NULL, 0, NULL, NULL ) ||
7497         broken(lRes == lstrlenW(dummy_window_text) + 37),
7498         "got bad length %ld\n", lRes );
7499
7500     ret = DestroyWindow(hwnd);
7501     ok( ret, "DestroyWindow() error %d\n", GetLastError());
7502 }
7503
7504 struct timer_info
7505 {
7506     HWND hWnd;
7507     HANDLE handles[2];
7508     DWORD id;
7509 };
7510
7511 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
7512 {
7513 }
7514
7515 #define TIMER_ID  0x19
7516
7517 static DWORD WINAPI timer_thread_proc(LPVOID x)
7518 {
7519     struct timer_info *info = x;
7520     DWORD r;
7521
7522     r = KillTimer(info->hWnd, 0x19);
7523     ok(r,"KillTimer failed in thread\n");
7524     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
7525     ok(r,"SetTimer failed in thread\n");
7526     ok(r==TIMER_ID,"SetTimer id different\n");
7527     r = SetEvent(info->handles[0]);
7528     ok(r,"SetEvent failed in thread\n");
7529     return 0;
7530 }
7531
7532 static void test_timers(void)
7533 {
7534     struct timer_info info;
7535     DWORD id;
7536
7537     info.hWnd = CreateWindow ("TestWindowClass", NULL,
7538        WS_OVERLAPPEDWINDOW ,
7539        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7540        NULL, NULL, 0);
7541
7542     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
7543     ok(info.id, "SetTimer failed\n");
7544     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
7545     info.handles[0] = CreateEvent(NULL,0,0,NULL);
7546     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
7547
7548     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
7549
7550     WaitForSingleObject(info.handles[1], INFINITE);
7551
7552     CloseHandle(info.handles[0]);
7553     CloseHandle(info.handles[1]);
7554
7555     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
7556
7557     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
7558 }
7559
7560 static int count = 0;
7561 static VOID CALLBACK callback_count(
7562     HWND hwnd,
7563     UINT uMsg,
7564     UINT_PTR idEvent,
7565     DWORD dwTime
7566 )
7567 {
7568     count++;
7569 }
7570
7571 static void test_timers_no_wnd(void)
7572 {
7573     UINT_PTR id, id2;
7574     MSG msg;
7575
7576     count = 0;
7577     id = SetTimer(NULL, 0, 100, callback_count);
7578     ok(id != 0, "did not get id from SetTimer.\n");
7579     id2 = SetTimer(NULL, id, 200, callback_count);
7580     ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
7581     Sleep(150);
7582     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7583     ok(count == 0, "did not get zero count as expected (%i).\n", count);
7584     Sleep(150);
7585     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7586     ok(count == 1, "did not get one count as expected (%i).\n", count);
7587     KillTimer(NULL, id);
7588     Sleep(250);
7589     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
7590     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
7591 }
7592
7593 /* Various win events with arbitrary parameters */
7594 static const struct message WmWinEventsSeq[] = {
7595     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7596     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7597     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7598     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7599     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7600     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7601     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7602     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7603     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7604     /* our win event hook ignores OBJID_CURSOR events */
7605     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
7606     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
7607     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
7608     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
7609     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
7610     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
7611     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
7612     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
7613     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
7614     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
7615     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
7616     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
7617     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
7618     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
7619     { 0 }
7620 };
7621 static const struct message WmWinEventCaretSeq[] = {
7622     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7623     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7624     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
7625     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
7626     { 0 }
7627 };
7628 static const struct message WmWinEventCaretSeq_2[] = {
7629     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7630     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7631     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
7632     { 0 }
7633 };
7634 static const struct message WmWinEventAlertSeq[] = {
7635     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
7636     { 0 }
7637 };
7638 static const struct message WmWinEventAlertSeq_2[] = {
7639     /* create window in the thread proc */
7640     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
7641     /* our test event */
7642     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
7643     { 0 }
7644 };
7645 static const struct message WmGlobalHookSeq_1[] = {
7646     /* create window in the thread proc */
7647     { HCBT_CREATEWND, hook|lparam, 0, 2 },
7648     /* our test events */
7649     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
7650     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
7651     { 0 }
7652 };
7653 static const struct message WmGlobalHookSeq_2[] = {
7654     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
7655     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
7656     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
7657     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
7658     { 0 }
7659 };
7660
7661 static const struct message WmMouseLLHookSeq[] = {
7662     { WM_MOUSEMOVE, hook },
7663     { WM_LBUTTONUP, hook },
7664     { WM_MOUSEMOVE, hook },
7665     { 0 }
7666 };
7667
7668 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
7669                                          DWORD event,
7670                                          HWND hwnd,
7671                                          LONG object_id,
7672                                          LONG child_id,
7673                                          DWORD thread_id,
7674                                          DWORD event_time)
7675 {
7676     char buf[256];
7677
7678     trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
7679            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
7680
7681     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7682     {
7683         if (!lstrcmpiA(buf, "TestWindowClass") ||
7684             !lstrcmpiA(buf, "static"))
7685         {
7686             struct message msg;
7687
7688             msg.message = event;
7689             msg.flags = winevent_hook|wparam|lparam;
7690             msg.wParam = object_id;
7691             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
7692             add_message(&msg);
7693         }
7694     }
7695 }
7696
7697 static HHOOK hCBT_global_hook;
7698 static DWORD cbt_global_hook_thread_id;
7699
7700 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
7701
7702     HWND hwnd;
7703     char buf[256];
7704
7705     trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam);
7706
7707     if (nCode == HCBT_SYSCOMMAND)
7708     {
7709         struct message msg;
7710
7711         msg.message = nCode;
7712         msg.flags = hook|wparam|lparam;
7713         msg.wParam = wParam;
7714         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7715         add_message(&msg);
7716
7717         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7718     }
7719     /* WH_MOUSE_LL hook */
7720     if (nCode == HC_ACTION)
7721     {
7722         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
7723
7724         /* we can't test for real mouse events */
7725         if (mhll->flags & LLMHF_INJECTED)
7726         {
7727             struct message msg;
7728
7729             memset (&msg, 0, sizeof (msg));
7730             msg.message = wParam;
7731             msg.flags = hook;
7732             add_message(&msg);
7733         }
7734         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7735     }
7736
7737     /* Log also SetFocus(0) calls */
7738     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
7739
7740     if (GetClassNameA(hwnd, buf, sizeof(buf)))
7741     {
7742         if (!lstrcmpiA(buf, "TestWindowClass") ||
7743             !lstrcmpiA(buf, "static"))
7744         {
7745             struct message msg;
7746
7747             msg.message = nCode;
7748             msg.flags = hook|wparam|lparam;
7749             msg.wParam = wParam;
7750             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
7751             add_message(&msg);
7752         }
7753     }
7754     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
7755 }
7756
7757 static DWORD WINAPI win_event_global_thread_proc(void *param)
7758 {
7759     HWND hwnd;
7760     MSG msg;
7761     HANDLE hevent = *(HANDLE *)param;
7762
7763     assert(pNotifyWinEvent);
7764
7765     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7766     assert(hwnd);
7767     trace("created thread window %p\n", hwnd);
7768
7769     *(HWND *)param = hwnd;
7770
7771     flush_sequence();
7772     /* this event should be received only by our new hook proc,
7773      * an old one does not expect an event from another thread.
7774      */
7775     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
7776     SetEvent(hevent);
7777
7778     while (GetMessage(&msg, 0, 0, 0))
7779     {
7780         TranslateMessage(&msg);
7781         DispatchMessage(&msg);
7782     }
7783     return 0;
7784 }
7785
7786 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
7787 {
7788     HWND hwnd;
7789     MSG msg;
7790     HANDLE hevent = *(HANDLE *)param;
7791
7792     flush_sequence();
7793     /* these events should be received only by our new hook proc,
7794      * an old one does not expect an event from another thread.
7795      */
7796
7797     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7798     assert(hwnd);
7799     trace("created thread window %p\n", hwnd);
7800
7801     *(HWND *)param = hwnd;
7802
7803     /* Windows doesn't like when a thread plays games with the focus,
7804        that leads to all kinds of misbehaviours and failures to activate
7805        a window. So, better keep next lines commented out.
7806     SetFocus(0);
7807     SetFocus(hwnd);*/
7808
7809     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7810     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7811
7812     SetEvent(hevent);
7813
7814     while (GetMessage(&msg, 0, 0, 0))
7815     {
7816         TranslateMessage(&msg);
7817         DispatchMessage(&msg);
7818     }
7819     return 0;
7820 }
7821
7822 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
7823 {
7824     HWND hwnd;
7825     MSG msg;
7826     HANDLE hevent = *(HANDLE *)param;
7827
7828     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
7829     assert(hwnd);
7830     trace("created thread window %p\n", hwnd);
7831
7832     *(HWND *)param = hwnd;
7833
7834     flush_sequence();
7835
7836     /* Windows doesn't like when a thread plays games with the focus,
7837      * that leads to all kinds of misbehaviours and failures to activate
7838      * a window. So, better don't generate a mouse click message below.
7839      */
7840     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
7841     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
7842     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
7843
7844     SetEvent(hevent);
7845     while (GetMessage(&msg, 0, 0, 0))
7846     {
7847         TranslateMessage(&msg);
7848         DispatchMessage(&msg);
7849     }
7850     return 0;
7851 }
7852
7853 static void test_winevents(void)
7854 {
7855     BOOL ret;
7856     MSG msg;
7857     HWND hwnd, hwnd2;
7858     UINT i;
7859     HANDLE hthread, hevent;
7860     DWORD tid;
7861     HWINEVENTHOOK hhook;
7862     const struct message *events = WmWinEventsSeq;
7863
7864     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
7865                            WS_OVERLAPPEDWINDOW,
7866                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7867                            NULL, NULL, 0);
7868     assert(hwnd);
7869
7870     /****** start of global hook test *************/
7871     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
7872     if (!hCBT_global_hook)
7873     {
7874         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7875         skip( "cannot set global hook\n" );
7876         return;
7877     }
7878
7879     hevent = CreateEventA(NULL, 0, 0, NULL);
7880     assert(hevent);
7881     hwnd2 = (HWND)hevent;
7882
7883     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
7884     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7885
7886     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7887
7888     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
7889
7890     flush_sequence();
7891     /* this one should be received only by old hook proc */
7892     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
7893     /* this one should be received only by old hook proc */
7894     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
7895
7896     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
7897
7898     ret = UnhookWindowsHookEx(hCBT_global_hook);
7899     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
7900
7901     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7902     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7903     CloseHandle(hthread);
7904     CloseHandle(hevent);
7905     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7906     /****** end of global hook test *************/
7907
7908     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
7909     {
7910         ok(DestroyWindow(hwnd), "failed to destroy window\n");
7911         return;
7912     }
7913
7914     flush_sequence();
7915
7916     if (0)
7917     {
7918     /* this test doesn't pass under Win9x */
7919     /* win2k ignores events with hwnd == 0 */
7920     SetLastError(0xdeadbeef);
7921     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
7922     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
7923        GetLastError() == 0xdeadbeef, /* Win9x */
7924        "unexpected error %d\n", GetLastError());
7925     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7926     }
7927
7928     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
7929         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
7930
7931     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
7932
7933     /****** start of event filtering test *************/
7934     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7935         EVENT_OBJECT_SHOW, /* 0x8002 */
7936         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
7937         GetModuleHandleA(0), win_event_global_hook_proc,
7938         GetCurrentProcessId(), 0,
7939         WINEVENT_INCONTEXT);
7940     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7941
7942     hevent = CreateEventA(NULL, 0, 0, NULL);
7943     assert(hevent);
7944     hwnd2 = (HWND)hevent;
7945
7946     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7947     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7948
7949     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7950
7951     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
7952
7953     flush_sequence();
7954     /* this one should be received only by old hook proc */
7955     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7956     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
7957     /* this one should be received only by old hook proc */
7958     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
7959
7960     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
7961
7962     ret = pUnhookWinEvent(hhook);
7963     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
7964
7965     PostThreadMessageA(tid, WM_QUIT, 0, 0);
7966     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7967     CloseHandle(hthread);
7968     CloseHandle(hevent);
7969     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
7970     /****** end of event filtering test *************/
7971
7972     /****** start of out of context event test *************/
7973     hhook = (HWINEVENTHOOK)pSetWinEventHook(
7974         EVENT_MIN, EVENT_MAX,
7975         0, win_event_global_hook_proc,
7976         GetCurrentProcessId(), 0,
7977         WINEVENT_OUTOFCONTEXT);
7978     ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
7979
7980     hevent = CreateEventA(NULL, 0, 0, NULL);
7981     assert(hevent);
7982     hwnd2 = (HWND)hevent;
7983
7984     flush_sequence();
7985
7986     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
7987     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
7988
7989     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
7990
7991     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
7992     /* process pending winevent messages */
7993     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
7994     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
7995
7996     flush_sequence();
7997     /* this one should be received only by old hook proc */
7998     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
7999     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
8000     /* this one should be received only by old hook proc */
8001     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
8002
8003     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
8004     /* process pending winevent messages */
8005     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
8006     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
8007
8008     ret = pUnhookWinEvent(hhook);
8009     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8010
8011     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8012     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8013     CloseHandle(hthread);
8014     CloseHandle(hevent);
8015     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8016     /****** end of out of context event test *************/
8017
8018     /****** start of MOUSE_LL hook test *************/
8019     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
8020     /* WH_MOUSE_LL is not supported on Win9x platforms */
8021     if (!hCBT_global_hook)
8022     {
8023         trace("Skipping WH_MOUSE_LL test on this platform\n");
8024         goto skip_mouse_ll_hook_test;
8025     }
8026
8027     hevent = CreateEventA(NULL, 0, 0, NULL);
8028     assert(hevent);
8029     hwnd2 = (HWND)hevent;
8030
8031     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
8032     ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
8033
8034     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
8035         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
8036
8037     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
8038     flush_sequence();
8039
8040     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
8041     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
8042     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
8043
8044     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
8045
8046     ret = UnhookWindowsHookEx(hCBT_global_hook);
8047     ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
8048
8049     PostThreadMessageA(tid, WM_QUIT, 0, 0);
8050     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8051     CloseHandle(hthread);
8052     CloseHandle(hevent);
8053     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
8054     /****** end of MOUSE_LL hook test *************/
8055 skip_mouse_ll_hook_test:
8056
8057     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8058 }
8059
8060 static void test_set_hook(void)
8061 {
8062     BOOL ret;
8063     HHOOK hhook;
8064     HWINEVENTHOOK hwinevent_hook;
8065
8066     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
8067     ok(hhook != 0, "local hook does not require hModule set to 0\n");
8068     UnhookWindowsHookEx(hhook);
8069
8070     if (0)
8071     {
8072     /* this test doesn't pass under Win9x: BUG! */
8073     SetLastError(0xdeadbeef);
8074     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
8075     ok(!hhook, "global hook requires hModule != 0\n");
8076     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
8077     }
8078
8079     SetLastError(0xdeadbeef);
8080     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
8081     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
8082     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
8083        GetLastError() == 0xdeadbeef, /* Win9x */
8084        "unexpected error %d\n", GetLastError());
8085
8086     SetLastError(0xdeadbeef);
8087     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
8088     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
8089        GetLastError() == 0xdeadbeef, /* Win9x */
8090        "unexpected error %d\n", GetLastError());
8091
8092     if (!pSetWinEventHook || !pUnhookWinEvent) return;
8093
8094     /* even process local incontext hooks require hmodule */
8095     SetLastError(0xdeadbeef);
8096     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8097         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
8098     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8099     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8100        GetLastError() == 0xdeadbeef, /* Win9x */
8101        "unexpected error %d\n", GetLastError());
8102
8103     /* even thread local incontext hooks require hmodule */
8104     SetLastError(0xdeadbeef);
8105     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8106         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
8107     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
8108     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
8109        GetLastError() == 0xdeadbeef, /* Win9x */
8110        "unexpected error %d\n", GetLastError());
8111
8112     if (0)
8113     {
8114     /* these 3 tests don't pass under Win9x */
8115     SetLastError(0xdeadbeef);
8116     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
8117         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8118     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8119     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8120
8121     SetLastError(0xdeadbeef);
8122     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
8123         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8124     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
8125     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
8126
8127     SetLastError(0xdeadbeef);
8128     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8129         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
8130     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
8131     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
8132     }
8133
8134     SetLastError(0xdeadbeef);
8135     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
8136         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
8137     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8138     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8139     ret = pUnhookWinEvent(hwinevent_hook);
8140     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8141
8142 todo_wine {
8143     /* This call succeeds under win2k SP4, but fails under Wine.
8144        Does win2k test/use passed process id? */
8145     SetLastError(0xdeadbeef);
8146     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
8147         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
8148     ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
8149     ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
8150     ret = pUnhookWinEvent(hwinevent_hook);
8151     ok( ret, "UnhookWinEvent error %d\n", GetLastError());
8152 }
8153
8154     SetLastError(0xdeadbeef);
8155     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
8156     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
8157         GetLastError() == 0xdeadbeef, /* Win9x */
8158         "unexpected error %d\n", GetLastError());
8159 }
8160
8161 static const struct message ScrollWindowPaint1[] = {
8162     { WM_PAINT, sent },
8163     { WM_ERASEBKGND, sent|beginpaint },
8164     { 0 }
8165 };
8166
8167 static const struct message ScrollWindowPaint2[] = {
8168     { WM_PAINT, sent },
8169     { 0 }
8170 };
8171
8172 static void test_scrollwindowex(void)
8173 {
8174     HWND hwnd, hchild;
8175     RECT rect={0,0,130,130};
8176
8177     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
8178             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
8179             100, 100, 200, 200, 0, 0, 0, NULL);
8180     ok (hwnd != 0, "Failed to create overlapped window\n");
8181     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
8182             WS_VISIBLE|WS_CAPTION|WS_CHILD,
8183             10, 10, 150, 150, hwnd, 0, 0, NULL);
8184     ok (hchild != 0, "Failed to create child\n");
8185     UpdateWindow(hwnd);
8186     flush_events();
8187     flush_sequence();
8188
8189     /* scroll without the child window */
8190     trace("start scroll\n");
8191     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8192             SW_ERASE|SW_INVALIDATE);
8193     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8194     trace("end scroll\n");
8195     flush_sequence();
8196     flush_events();
8197     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8198     flush_events();
8199     flush_sequence();
8200
8201     /* Now without the SW_ERASE flag */
8202     trace("start scroll\n");
8203     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
8204     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8205     trace("end scroll\n");
8206     flush_sequence();
8207     flush_events();
8208     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
8209     flush_events();
8210     flush_sequence();
8211
8212     /* now scroll the child window as well */
8213     trace("start scroll\n");
8214     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
8215             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
8216     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
8217                 /* windows sometimes a WM_MOVE */
8218         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
8219     }
8220     trace("end scroll\n");
8221     flush_sequence();
8222     flush_events();
8223     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
8224     flush_events();
8225     flush_sequence();
8226
8227     /* now scroll with ScrollWindow() */
8228     trace("start scroll with ScrollWindow\n");
8229     ScrollWindow( hwnd, 5, 5, NULL, NULL);
8230     trace("end scroll\n");
8231     flush_sequence();
8232     flush_events();
8233     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
8234
8235     ok(DestroyWindow(hchild), "failed to destroy window\n");
8236     ok(DestroyWindow(hwnd), "failed to destroy window\n");
8237     flush_sequence();
8238 }
8239
8240 static const struct message destroy_window_with_children[] = {
8241     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8242     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
8243     { 0x0090, sent|optional },
8244     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
8245     { 0x0090, sent|optional },
8246     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
8247     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8248     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8249     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
8250     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
8251     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8252     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8253     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8254     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8255     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
8256     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
8257     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
8258     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
8259     { 0 }
8260 };
8261
8262 static void test_DestroyWindow(void)
8263 {
8264     BOOL ret;
8265     HWND parent, child1, child2, child3, child4, test;
8266     UINT child_id = WND_CHILD_ID + 1;
8267
8268     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8269                              100, 100, 200, 200, 0, 0, 0, NULL);
8270     assert(parent != 0);
8271     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8272                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
8273     assert(child1 != 0);
8274     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8275                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
8276     assert(child2 != 0);
8277     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
8278                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
8279     assert(child3 != 0);
8280     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
8281                              0, 0, 50, 50, parent, 0, 0, NULL);
8282     assert(child4 != 0);
8283
8284     /* test owner/parent of child2 */
8285     test = GetParent(child2);
8286     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8287     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8288     if(pGetAncestor) {
8289         test = pGetAncestor(child2, GA_PARENT);
8290         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8291     }
8292     test = GetWindow(child2, GW_OWNER);
8293     ok(!test, "wrong owner %p\n", test);
8294
8295     test = SetParent(child2, parent);
8296     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
8297
8298     /* test owner/parent of the parent */
8299     test = GetParent(parent);
8300     ok(!test, "wrong parent %p\n", test);
8301     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
8302     if(pGetAncestor) {
8303         test = pGetAncestor(parent, GA_PARENT);
8304         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8305     }
8306     test = GetWindow(parent, GW_OWNER);
8307     ok(!test, "wrong owner %p\n", test);
8308
8309     /* test owner/parent of child1 */
8310     test = GetParent(child1);
8311     ok(test == parent, "wrong parent %p\n", test);
8312     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
8313     if(pGetAncestor) {
8314         test = pGetAncestor(child1, GA_PARENT);
8315         ok(test == parent, "wrong parent %p\n", test);
8316     }
8317     test = GetWindow(child1, GW_OWNER);
8318     ok(!test, "wrong owner %p\n", test);
8319
8320     /* test owner/parent of child2 */
8321     test = GetParent(child2);
8322     ok(test == parent, "wrong parent %p\n", test);
8323     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
8324     if(pGetAncestor) {
8325         test = pGetAncestor(child2, GA_PARENT);
8326         ok(test == parent, "wrong parent %p\n", test);
8327     }
8328     test = GetWindow(child2, GW_OWNER);
8329     ok(!test, "wrong owner %p\n", test);
8330
8331     /* test owner/parent of child3 */
8332     test = GetParent(child3);
8333     ok(test == child1, "wrong parent %p\n", test);
8334     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
8335     if(pGetAncestor) {
8336         test = pGetAncestor(child3, GA_PARENT);
8337         ok(test == child1, "wrong parent %p\n", test);
8338     }
8339     test = GetWindow(child3, GW_OWNER);
8340     ok(!test, "wrong owner %p\n", test);
8341
8342     /* test owner/parent of child4 */
8343     test = GetParent(child4);
8344     ok(test == parent, "wrong parent %p\n", test);
8345     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
8346     if(pGetAncestor) {
8347         test = pGetAncestor(child4, GA_PARENT);
8348         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
8349     }
8350     test = GetWindow(child4, GW_OWNER);
8351     ok(test == parent, "wrong owner %p\n", test);
8352
8353     flush_sequence();
8354
8355     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
8356            parent, child1, child2, child3, child4);
8357
8358     SetCapture(child4);
8359     test = GetCapture();
8360     ok(test == child4, "wrong capture window %p\n", test);
8361
8362     test_DestroyWindow_flag = TRUE;
8363     ret = DestroyWindow(parent);
8364     ok( ret, "DestroyWindow() error %d\n", GetLastError());
8365     test_DestroyWindow_flag = FALSE;
8366     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
8367
8368     ok(!IsWindow(parent), "parent still exists\n");
8369     ok(!IsWindow(child1), "child1 still exists\n");
8370     ok(!IsWindow(child2), "child2 still exists\n");
8371     ok(!IsWindow(child3), "child3 still exists\n");
8372     ok(!IsWindow(child4), "child4 still exists\n");
8373
8374     test = GetCapture();
8375     ok(!test, "wrong capture window %p\n", test);
8376 }
8377
8378
8379 static const struct message WmDispatchPaint[] = {
8380     { WM_NCPAINT, sent },
8381     { WM_GETTEXT, sent|defwinproc|optional },
8382     { WM_GETTEXT, sent|defwinproc|optional },
8383     { WM_ERASEBKGND, sent },
8384     { 0 }
8385 };
8386
8387 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8388 {
8389     if (message == WM_PAINT) return 0;
8390     return MsgCheckProcA( hwnd, message, wParam, lParam );
8391 }
8392
8393 static void test_DispatchMessage(void)
8394 {
8395     RECT rect;
8396     MSG msg;
8397     int count;
8398     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8399                                100, 100, 200, 200, 0, 0, 0, NULL);
8400     ShowWindow( hwnd, SW_SHOW );
8401     UpdateWindow( hwnd );
8402     flush_events();
8403     flush_sequence();
8404     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
8405
8406     SetRect( &rect, -5, -5, 5, 5 );
8407     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8408     count = 0;
8409     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8410     {
8411         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8412         else
8413         {
8414             flush_sequence();
8415             DispatchMessage( &msg );
8416             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
8417             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8418             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
8419             if (++count > 10) break;
8420         }
8421     }
8422     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
8423
8424     trace("now without DispatchMessage\n");
8425     flush_sequence();
8426     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
8427     count = 0;
8428     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
8429     {
8430         if (msg.message != WM_PAINT) DispatchMessage( &msg );
8431         else
8432         {
8433             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
8434             flush_sequence();
8435             /* this will send WM_NCCPAINT just like DispatchMessage does */
8436             GetUpdateRgn( hwnd, hrgn, TRUE );
8437             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
8438             DeleteObject( hrgn );
8439             GetClientRect( hwnd, &rect );
8440             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
8441             ok( !count, "Got multiple WM_PAINTs\n" );
8442             if (++count > 10) break;
8443         }
8444     }
8445     DestroyWindow(hwnd);
8446 }
8447
8448
8449 static const struct message WmUser[] = {
8450     { WM_USER, sent },
8451     { 0 }
8452 };
8453
8454 struct sendmsg_info
8455 {
8456     HWND  hwnd;
8457     DWORD timeout;
8458     DWORD ret;
8459 };
8460
8461 static DWORD CALLBACK send_msg_thread( LPVOID arg )
8462 {
8463     struct sendmsg_info *info = arg;
8464     SetLastError( 0xdeadbeef );
8465     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
8466     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
8467                         broken(GetLastError() == 0),  /* win9x */
8468                         "unexpected error %d\n", GetLastError());
8469     return 0;
8470 }
8471
8472 static void wait_for_thread( HANDLE thread )
8473 {
8474     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
8475     {
8476         MSG msg;
8477         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
8478     }
8479 }
8480
8481 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8482 {
8483     if (message == WM_USER) Sleep(200);
8484     return MsgCheckProcA( hwnd, message, wParam, lParam );
8485 }
8486
8487 static void test_SendMessageTimeout(void)
8488 {
8489     HANDLE thread;
8490     struct sendmsg_info info;
8491     DWORD tid;
8492     BOOL is_win9x;
8493
8494     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8495                                100, 100, 200, 200, 0, 0, 0, NULL);
8496     flush_events();
8497     flush_sequence();
8498
8499     info.timeout = 1000;
8500     info.ret = 0xdeadbeef;
8501     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8502     wait_for_thread( thread );
8503     CloseHandle( thread );
8504     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8505     ok_sequence( WmUser, "WmUser", FALSE );
8506
8507     info.timeout = 1;
8508     info.ret = 0xdeadbeef;
8509     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8510     Sleep(100);  /* SendMessageTimeout should time out here */
8511     wait_for_thread( thread );
8512     CloseHandle( thread );
8513     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8514     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8515
8516     /* 0 means infinite timeout (but not on win9x) */
8517     info.timeout = 0;
8518     info.ret = 0xdeadbeef;
8519     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8520     Sleep(100);
8521     wait_for_thread( thread );
8522     CloseHandle( thread );
8523     is_win9x = !info.ret;
8524     if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8525     else ok_sequence( WmUser, "WmUser", FALSE );
8526
8527     /* timeout is treated as signed despite the prototype (but not on win9x) */
8528     info.timeout = 0x7fffffff;
8529     info.ret = 0xdeadbeef;
8530     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8531     Sleep(100);
8532     wait_for_thread( thread );
8533     CloseHandle( thread );
8534     ok( info.ret == 1, "SendMessageTimeout failed\n" );
8535     ok_sequence( WmUser, "WmUser", FALSE );
8536
8537     info.timeout = 0x80000000;
8538     info.ret = 0xdeadbeef;
8539     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8540     Sleep(100);
8541     wait_for_thread( thread );
8542     CloseHandle( thread );
8543     if (is_win9x)
8544     {
8545         ok( info.ret == 1, "SendMessageTimeout failed\n" );
8546         ok_sequence( WmUser, "WmUser", FALSE );
8547     }
8548     else
8549     {
8550         ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
8551         ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
8552     }
8553
8554     /* now check for timeout during message processing */
8555     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
8556     info.timeout = 100;
8557     info.ret = 0xdeadbeef;
8558     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
8559     wait_for_thread( thread );
8560     CloseHandle( thread );
8561     /* we should time out but still get the message */
8562     ok( info.ret == 0, "SendMessageTimeout failed\n" );
8563     ok_sequence( WmUser, "WmUser", FALSE );
8564
8565     DestroyWindow( info.hwnd );
8566 }
8567
8568
8569 /****************** edit message test *************************/
8570 #define ID_EDIT 0x1234
8571 static const struct message sl_edit_setfocus[] =
8572 {
8573     { HCBT_SETFOCUS, hook },
8574     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8575     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8576     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8577     { WM_SETFOCUS, sent|wparam, 0 },
8578     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8579     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
8580     { WM_CTLCOLOREDIT, sent|parent },
8581     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8582     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8583     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8584     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8585     { 0 }
8586 };
8587 static const struct message ml_edit_setfocus[] =
8588 {
8589     { HCBT_SETFOCUS, hook },
8590     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
8591     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8592     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8593     { WM_SETFOCUS, sent|wparam, 0 },
8594     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8595     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8596     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8597     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8598     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8599     { 0 }
8600 };
8601 static const struct message sl_edit_killfocus[] =
8602 {
8603     { HCBT_SETFOCUS, hook },
8604     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8605     { WM_KILLFOCUS, sent|wparam, 0 },
8606     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8607     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8608     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
8609     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
8610     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
8611     { 0 }
8612 };
8613 static const struct message sl_edit_lbutton_dblclk[] =
8614 {
8615     { WM_LBUTTONDBLCLK, sent },
8616     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8617     { 0 }
8618 };
8619 static const struct message sl_edit_lbutton_down[] =
8620 {
8621     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8622     { HCBT_SETFOCUS, hook },
8623     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8624     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8625     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8626     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8627     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8628     { WM_CTLCOLOREDIT, sent|parent },
8629     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8630     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8631     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8632     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8633     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8634     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8635     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8636     { WM_CTLCOLOREDIT, sent|parent|optional },
8637     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8638     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8639     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8640     { 0 }
8641 };
8642 static const struct message ml_edit_lbutton_down[] =
8643 {
8644     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
8645     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8646     { HCBT_SETFOCUS, hook },
8647     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
8648     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
8649     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
8650     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
8651     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
8652     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
8653     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8654     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8655     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
8656     { 0 }
8657 };
8658 static const struct message sl_edit_lbutton_up[] =
8659 {
8660     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8661     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8662     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8663     { WM_CAPTURECHANGED, sent|defwinproc },
8664     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
8665     { 0 }
8666 };
8667 static const struct message ml_edit_lbutton_up[] =
8668 {
8669     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
8670     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8671     { WM_CAPTURECHANGED, sent|defwinproc },
8672     { 0 }
8673 };
8674
8675 static WNDPROC old_edit_proc;
8676
8677 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
8678 {
8679     static long defwndproc_counter = 0;
8680     LRESULT ret;
8681     struct message msg;
8682
8683     trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
8684
8685     /* explicitly ignore WM_GETICON message */
8686     if (message == WM_GETICON) return 0;
8687
8688     /* ignore registered messages */
8689     if (message >= 0xc000) return 0;
8690
8691     msg.message = message;
8692     msg.flags = sent|wparam|lparam;
8693     if (defwndproc_counter) msg.flags |= defwinproc;
8694     msg.wParam = wParam;
8695     msg.lParam = lParam;
8696     add_message(&msg);
8697
8698     defwndproc_counter++;
8699     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
8700     defwndproc_counter--;
8701
8702     return ret;
8703 }
8704
8705 static void subclass_edit(void)
8706 {
8707     WNDCLASSA cls;
8708
8709     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
8710
8711     old_edit_proc = cls.lpfnWndProc;
8712
8713     cls.hInstance = GetModuleHandle(0);
8714     cls.lpfnWndProc = edit_hook_proc;
8715     cls.lpszClassName = "my_edit_class";
8716     UnregisterClass(cls.lpszClassName, cls.hInstance);
8717     if (!RegisterClassA(&cls)) assert(0);
8718 }
8719
8720 static void test_edit_messages(void)
8721 {
8722     HWND hwnd, parent;
8723     DWORD dlg_code;
8724
8725     subclass_edit();
8726     log_all_parent_messages++;
8727
8728     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8729                              100, 100, 200, 200, 0, 0, 0, NULL);
8730     ok (parent != 0, "Failed to create parent window\n");
8731
8732     /* test single line edit */
8733     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
8734                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8735     ok(hwnd != 0, "Failed to create edit window\n");
8736
8737     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8738     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
8739
8740     ShowWindow(hwnd, SW_SHOW);
8741     UpdateWindow(hwnd);
8742     SetFocus(0);
8743     flush_sequence();
8744
8745     SetFocus(hwnd);
8746     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
8747
8748     SetFocus(0);
8749     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
8750
8751     SetFocus(0);
8752     ReleaseCapture();
8753     flush_sequence();
8754
8755     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8756     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
8757
8758     SetFocus(0);
8759     ReleaseCapture();
8760     flush_sequence();
8761
8762     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8763     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
8764
8765     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8766     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
8767
8768     DestroyWindow(hwnd);
8769
8770     /* test multiline edit */
8771     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
8772                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
8773     ok(hwnd != 0, "Failed to create edit window\n");
8774
8775     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
8776     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
8777        "wrong dlg_code %08x\n", dlg_code);
8778
8779     ShowWindow(hwnd, SW_SHOW);
8780     UpdateWindow(hwnd);
8781     SetFocus(0);
8782     flush_sequence();
8783
8784     SetFocus(hwnd);
8785     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
8786
8787     SetFocus(0);
8788     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
8789
8790     SetFocus(0);
8791     ReleaseCapture();
8792     flush_sequence();
8793
8794     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
8795     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
8796
8797     SetFocus(0);
8798     ReleaseCapture();
8799     flush_sequence();
8800
8801     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
8802     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
8803
8804     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
8805     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
8806
8807     DestroyWindow(hwnd);
8808     DestroyWindow(parent);
8809
8810     log_all_parent_messages--;
8811 }
8812
8813 /**************************** End of Edit test ******************************/
8814
8815 static const struct message WmKeyDownSkippedSeq[] =
8816 {
8817     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8818     { 0 }
8819 };
8820 static const struct message WmKeyUpSkippedSeq[] =
8821 {
8822     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8823     { 0 }
8824 };
8825
8826 #define EV_STOP 0
8827 #define EV_SENDMSG 1
8828 #define EV_ACK 2
8829
8830 struct peekmsg_info
8831 {
8832     HWND  hwnd;
8833     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
8834 };
8835
8836 static DWORD CALLBACK send_msg_thread_2(void *param)
8837 {
8838     DWORD ret;
8839     struct peekmsg_info *info = param;
8840
8841     trace("thread: looping\n");
8842     SetEvent(info->hevent[EV_ACK]);
8843
8844     while (1)
8845     {
8846         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
8847
8848         switch (ret)
8849         {
8850         case WAIT_OBJECT_0 + EV_STOP:
8851             trace("thread: exiting\n");
8852             return 0;
8853
8854         case WAIT_OBJECT_0 + EV_SENDMSG:
8855             trace("thread: sending message\n");
8856             ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
8857                 "SendNotifyMessageA failed error %u\n", GetLastError());
8858             SetEvent(info->hevent[EV_ACK]);
8859             break;
8860
8861         default:
8862             trace("unexpected return: %04x\n", ret);
8863             assert(0);
8864             break;
8865         }
8866     }
8867     return 0;
8868 }
8869
8870 static void test_PeekMessage(void)
8871 {
8872     MSG msg;
8873     HANDLE hthread;
8874     DWORD tid, qstatus;
8875     UINT qs_all_input = QS_ALLINPUT;
8876     UINT qs_input = QS_INPUT;
8877     BOOL ret;
8878     struct peekmsg_info info;
8879
8880     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
8881                               100, 100, 200, 200, 0, 0, 0, NULL);
8882     assert(info.hwnd);
8883     ShowWindow(info.hwnd, SW_SHOW);
8884     UpdateWindow(info.hwnd);
8885     SetFocus(info.hwnd);
8886
8887     info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
8888     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
8889     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
8890
8891     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
8892     WaitForSingleObject(info.hevent[EV_ACK], 10000);
8893
8894     flush_events();
8895     flush_sequence();
8896
8897     SetLastError(0xdeadbeef);
8898     qstatus = GetQueueStatus(qs_all_input);
8899     if (GetLastError() == ERROR_INVALID_FLAGS)
8900     {
8901         trace("QS_RAWINPUT not supported on this platform\n");
8902         qs_all_input &= ~QS_RAWINPUT;
8903         qs_input &= ~QS_RAWINPUT;
8904     }
8905     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8906
8907     trace("signalling to send message\n");
8908     SetEvent(info.hevent[EV_SENDMSG]);
8909     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8910
8911     /* pass invalid QS_xxxx flags */
8912     SetLastError(0xdeadbeef);
8913     qstatus = GetQueueStatus(0xffffffff);
8914     ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
8915     if (!qstatus)
8916     {
8917         ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
8918         qstatus = GetQueueStatus(qs_all_input);
8919     }
8920     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
8921        "wrong qstatus %08x\n", qstatus);
8922
8923     msg.message = 0;
8924     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
8925     ok(!ret,
8926        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8927         msg.message);
8928     ok_sequence(WmUser, "WmUser", FALSE);
8929
8930     qstatus = GetQueueStatus(qs_all_input);
8931     ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
8932
8933     keybd_event('N', 0, 0, 0);
8934     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8935     qstatus = GetQueueStatus(qs_all_input);
8936     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
8937        "wrong qstatus %08x\n", qstatus);
8938
8939     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
8940     qstatus = GetQueueStatus(qs_all_input);
8941     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
8942        "wrong qstatus %08x\n", qstatus);
8943
8944     InvalidateRect(info.hwnd, NULL, FALSE);
8945     qstatus = GetQueueStatus(qs_all_input);
8946     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8947        "wrong qstatus %08x\n", qstatus);
8948
8949     trace("signalling to send message\n");
8950     SetEvent(info.hevent[EV_SENDMSG]);
8951     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8952
8953     qstatus = GetQueueStatus(qs_all_input);
8954     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8955        "wrong qstatus %08x\n", qstatus);
8956
8957     msg.message = 0;
8958     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
8959     if (ret && msg.message == WM_CHAR)
8960     {
8961         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
8962         goto done;
8963     }
8964     ok(!ret,
8965        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8966         msg.message);
8967     if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
8968     {
8969         win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
8970         goto done;
8971     }
8972     ok_sequence(WmUser, "WmUser", FALSE);
8973
8974     qstatus = GetQueueStatus(qs_all_input);
8975     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8976        "wrong qstatus %08x\n", qstatus);
8977
8978     trace("signalling to send message\n");
8979     SetEvent(info.hevent[EV_SENDMSG]);
8980     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
8981
8982     qstatus = GetQueueStatus(qs_all_input);
8983     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8984        "wrong qstatus %08x\n", qstatus);
8985
8986     msg.message = 0;
8987     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
8988     ok(!ret,
8989        "PeekMessageA should have returned FALSE instead of msg %04x\n",
8990         msg.message);
8991     ok_sequence(WmUser, "WmUser", FALSE);
8992
8993     qstatus = GetQueueStatus(qs_all_input);
8994     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
8995        "wrong qstatus %08x\n", qstatus);
8996
8997     msg.message = 0;
8998     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
8999     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9000        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9001        ret, msg.message, msg.wParam);
9002     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9003
9004     qstatus = GetQueueStatus(qs_all_input);
9005     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9006        "wrong qstatus %08x\n", qstatus);
9007
9008     msg.message = 0;
9009     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
9010     ok(!ret,
9011        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9012         msg.message);
9013     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9014
9015     qstatus = GetQueueStatus(qs_all_input);
9016     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
9017        "wrong qstatus %08x\n", qstatus);
9018
9019     msg.message = 0;
9020     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9021     ok(ret && msg.message == WM_PAINT,
9022        "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
9023     DispatchMessageA(&msg);
9024     ok_sequence(WmPaint, "WmPaint", FALSE);
9025
9026     qstatus = GetQueueStatus(qs_all_input);
9027     ok(qstatus == MAKELONG(0, QS_KEY),
9028        "wrong qstatus %08x\n", qstatus);
9029
9030     msg.message = 0;
9031     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
9032     ok(!ret,
9033        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9034         msg.message);
9035     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9036
9037     qstatus = GetQueueStatus(qs_all_input);
9038     ok(qstatus == MAKELONG(0, QS_KEY),
9039        "wrong qstatus %08x\n", qstatus);
9040
9041     trace("signalling to send message\n");
9042     SetEvent(info.hevent[EV_SENDMSG]);
9043     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9044
9045     qstatus = GetQueueStatus(qs_all_input);
9046     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
9047        "wrong qstatus %08x\n", qstatus);
9048
9049     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9050
9051     qstatus = GetQueueStatus(qs_all_input);
9052     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9053        "wrong qstatus %08x\n", qstatus);
9054
9055     msg.message = 0;
9056     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9057     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9058        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9059        ret, msg.message, msg.wParam);
9060     ok_sequence(WmUser, "WmUser", FALSE);
9061
9062     qstatus = GetQueueStatus(qs_all_input);
9063     ok(qstatus == MAKELONG(0, QS_KEY),
9064        "wrong qstatus %08x\n", qstatus);
9065
9066     msg.message = 0;
9067     ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
9068     ok(!ret,
9069        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9070         msg.message);
9071     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9072
9073     qstatus = GetQueueStatus(qs_all_input);
9074     ok(qstatus == MAKELONG(0, QS_KEY),
9075        "wrong qstatus %08x\n", qstatus);
9076
9077     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9078
9079     qstatus = GetQueueStatus(qs_all_input);
9080     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
9081        "wrong qstatus %08x\n", qstatus);
9082
9083     trace("signalling to send message\n");
9084     SetEvent(info.hevent[EV_SENDMSG]);
9085     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9086
9087     qstatus = GetQueueStatus(qs_all_input);
9088     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9089        "wrong qstatus %08x\n", qstatus);
9090
9091     msg.message = 0;
9092     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
9093     ok(!ret,
9094        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9095         msg.message);
9096     ok_sequence(WmUser, "WmUser", FALSE);
9097
9098     qstatus = GetQueueStatus(qs_all_input);
9099     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9100        "wrong qstatus %08x\n", qstatus);
9101
9102     msg.message = 0;
9103     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9104         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9105     else /* workaround for a missing QS_RAWINPUT support */
9106         ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
9107     ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9108        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9109        ret, msg.message, msg.wParam);
9110     ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
9111
9112     qstatus = GetQueueStatus(qs_all_input);
9113     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
9114        "wrong qstatus %08x\n", qstatus);
9115
9116     msg.message = 0;
9117     if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
9118         ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
9119     else /* workaround for a missing QS_RAWINPUT support */
9120         ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
9121     ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9122        "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
9123        ret, msg.message, msg.wParam);
9124     ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
9125
9126     qstatus = GetQueueStatus(qs_all_input);
9127     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9128        "wrong qstatus %08x\n", qstatus);
9129
9130     msg.message = 0;
9131     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
9132     ok(!ret,
9133        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9134         msg.message);
9135     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9136
9137     qstatus = GetQueueStatus(qs_all_input);
9138     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9139        "wrong qstatus %08x\n", qstatus);
9140
9141     msg.message = 0;
9142     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9143     ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9144        "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9145        ret, msg.message, msg.wParam);
9146     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9147
9148     qstatus = GetQueueStatus(qs_all_input);
9149     ok(qstatus == 0,
9150        "wrong qstatus %08x\n", qstatus);
9151
9152     msg.message = 0;
9153     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9154     ok(!ret,
9155        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9156         msg.message);
9157     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9158
9159     qstatus = GetQueueStatus(qs_all_input);
9160     ok(qstatus == 0,
9161        "wrong qstatus %08x\n", qstatus);
9162
9163     /* test whether presence of the quit flag in the queue affects
9164      * the queue state
9165      */
9166     PostQuitMessage(0x1234abcd);
9167
9168     qstatus = GetQueueStatus(qs_all_input);
9169     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9170        "wrong qstatus %08x\n", qstatus);
9171
9172     PostMessageA(info.hwnd, WM_USER, 0, 0);
9173
9174     qstatus = GetQueueStatus(qs_all_input);
9175     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
9176        "wrong qstatus %08x\n", qstatus);
9177
9178     msg.message = 0;
9179     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9180     ok(ret && msg.message == WM_USER,
9181        "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
9182     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9183
9184     qstatus = GetQueueStatus(qs_all_input);
9185     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9186        "wrong qstatus %08x\n", qstatus);
9187
9188     msg.message = 0;
9189     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9190     ok(ret && msg.message == WM_QUIT,
9191        "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
9192     ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
9193     ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
9194     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9195
9196     qstatus = GetQueueStatus(qs_all_input);
9197 todo_wine {
9198     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
9199        "wrong qstatus %08x\n", qstatus);
9200 }
9201
9202     msg.message = 0;
9203     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
9204     ok(!ret,
9205        "PeekMessageA should have returned FALSE instead of msg %04x\n",
9206         msg.message);
9207     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
9208
9209     qstatus = GetQueueStatus(qs_all_input);
9210     ok(qstatus == 0,
9211        "wrong qstatus %08x\n", qstatus);
9212
9213     /* some GetMessage tests */
9214
9215     keybd_event('N', 0, 0, 0);
9216     qstatus = GetQueueStatus(qs_all_input);
9217     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9218
9219     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9220     qstatus = GetQueueStatus(qs_all_input);
9221     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9222
9223     if (qstatus)
9224     {
9225         ret = GetMessageA( &msg, 0, 0, 0 );
9226         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9227            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9228            ret, msg.message, msg.wParam);
9229         qstatus = GetQueueStatus(qs_all_input);
9230         ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
9231     }
9232
9233     if (qstatus)
9234     {
9235         ret = GetMessageA( &msg, 0, 0, 0 );
9236         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9237            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9238            ret, msg.message, msg.wParam);
9239         qstatus = GetQueueStatus(qs_all_input);
9240         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9241     }
9242
9243     keybd_event('N', 0, 0, 0);
9244     qstatus = GetQueueStatus(qs_all_input);
9245     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9246
9247     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9248     qstatus = GetQueueStatus(qs_all_input);
9249     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9250
9251     if (qstatus & (QS_KEY << 16))
9252     {
9253         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9254         ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
9255            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9256            ret, msg.message, msg.wParam);
9257         qstatus = GetQueueStatus(qs_all_input);
9258         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9259     }
9260
9261     if (qstatus)
9262     {
9263         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9264         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9265            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9266            ret, msg.message, msg.wParam);
9267         qstatus = GetQueueStatus(qs_all_input);
9268         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9269     }
9270
9271     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9272     qstatus = GetQueueStatus(qs_all_input);
9273     ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
9274
9275     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
9276     qstatus = GetQueueStatus(qs_all_input);
9277     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
9278
9279     trace("signalling to send message\n");
9280     SetEvent(info.hevent[EV_SENDMSG]);
9281     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
9282     qstatus = GetQueueStatus(qs_all_input);
9283     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
9284        "wrong qstatus %08x\n", qstatus);
9285
9286     if (qstatus & (QS_KEY << 16))
9287     {
9288         ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
9289         ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
9290            "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
9291            ret, msg.message, msg.wParam);
9292         ok_sequence(WmUser, "WmUser", FALSE);
9293         qstatus = GetQueueStatus(qs_all_input);
9294         ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
9295     }
9296
9297     if (qstatus)
9298     {
9299         ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
9300         ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
9301            "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
9302            ret, msg.message, msg.wParam);
9303         qstatus = GetQueueStatus(qs_all_input);
9304         ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
9305     }
9306 done:
9307     trace("signalling to exit\n");
9308     SetEvent(info.hevent[EV_STOP]);
9309
9310     WaitForSingleObject(hthread, INFINITE);
9311
9312     CloseHandle(hthread);
9313     CloseHandle(info.hevent[0]);
9314     CloseHandle(info.hevent[1]);
9315     CloseHandle(info.hevent[2]);
9316
9317     DestroyWindow(info.hwnd);
9318 }
9319
9320 static void wait_move_event(HWND hwnd, int x, int y)
9321 {
9322     MSG msg;
9323     DWORD time;
9324     BOOL  ret;
9325     int go = 0;
9326
9327     time = GetTickCount();
9328     while (GetTickCount() - time < 200 && !go) {
9329         ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9330         go  = ret && msg.pt.x > x && msg.pt.y > y;
9331     }
9332 }
9333
9334 #define STEP 20
9335 static void test_PeekMessage2(void)
9336 {
9337     HWND hwnd;
9338     BOOL ret;
9339     MSG msg;
9340     UINT message;
9341     DWORD time1, time2, time3;
9342     int x1, y1, x2, y2, x3, y3;
9343     POINT pos;
9344
9345     time1 = time2 = time3 = 0;
9346     x1 = y1 = x2 = y2 = x3 = y3 = 0;
9347
9348     /* Initialise window and make sure it is ready for events */
9349     hwnd = CreateWindow("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
9350                         10, 10, 800, 800, NULL, NULL, NULL, NULL);
9351     assert(hwnd);
9352     trace("Window for test_PeekMessage2 %p\n", hwnd);
9353     ShowWindow(hwnd, SW_SHOW);
9354     UpdateWindow(hwnd);
9355     SetFocus(hwnd);
9356     GetCursorPos(&pos);
9357     SetCursorPos(100, 100);
9358     mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
9359     flush_events();
9360
9361     /* Do initial mousemove, wait until we can see it
9362        and then do our test peek with PM_NOREMOVE. */
9363     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9364     wait_move_event(hwnd, 80, 80);
9365
9366     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9367     ok(ret, "no message available\n");
9368     if (ret) {
9369         trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9370         message = msg.message;
9371         time1 = msg.time;
9372         x1 = msg.pt.x;
9373         y1 = msg.pt.y;
9374         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9375     }
9376
9377     /* Allow time to advance a bit, and then simulate the user moving their
9378      * mouse around. After that we peek again with PM_NOREMOVE.
9379      * Although the previous mousemove message was never removed, the
9380      * mousemove we now peek should reflect the recent mouse movements
9381      * because the input queue will merge the move events. */
9382     Sleep(2);
9383     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9384     wait_move_event(hwnd, x1, y1);
9385
9386     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9387     ok(ret, "no message available\n");
9388     if (ret) {
9389         trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9390         message = msg.message;
9391         time2 = msg.time;
9392         x2 = msg.pt.x;
9393         y2 = msg.pt.y;
9394         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9395         ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
9396         ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
9397     }
9398
9399     /* Have another go, to drive the point home */
9400     Sleep(2);
9401     mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
9402     wait_move_event(hwnd, x2, y2);
9403
9404     ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
9405     ok(ret, "no message available\n");
9406     if (ret) {
9407         trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
9408         message = msg.message;
9409         time3 = msg.time;
9410         x3 = msg.pt.x;
9411         y3 = msg.pt.y;
9412         ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
9413         ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
9414         ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
9415     }
9416
9417     DestroyWindow(hwnd);
9418     SetCursorPos(pos.x, pos.y);
9419     flush_events();
9420 }
9421
9422 static void test_quit_message(void)
9423 {
9424     MSG msg;
9425     BOOL ret;
9426
9427     /* test using PostQuitMessage */
9428     flush_events();
9429     PostQuitMessage(0xbeef);
9430
9431     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9432     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9433     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9434     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9435
9436     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9437     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9438
9439     ret = GetMessage(&msg, NULL, 0, 0);
9440     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9441     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9442
9443     /* note: WM_QUIT message received after WM_USER message */
9444     ret = GetMessage(&msg, NULL, 0, 0);
9445     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9446     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9447     ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
9448
9449     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
9450     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
9451
9452     /* now test with PostThreadMessage - different behaviour! */
9453     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
9454
9455     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
9456     ok(ret, "PeekMessage failed with error %d\n", GetLastError());
9457     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9458     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9459
9460     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
9461     ok(ret, "PostMessage failed with error %d\n", GetLastError());
9462
9463     /* note: we receive the WM_QUIT message first this time */
9464     ret = GetMessage(&msg, NULL, 0, 0);
9465     ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
9466     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
9467     ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
9468
9469     ret = GetMessage(&msg, NULL, 0, 0);
9470     ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
9471     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
9472 }
9473
9474 static const struct message WmMouseHoverSeq[] = {
9475     { WM_MOUSEACTIVATE, sent|optional },  /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
9476     { WM_MOUSEACTIVATE, sent|optional },
9477     { WM_TIMER, sent|optional }, /* XP sends it */
9478     { WM_SYSTIMER, sent },
9479     { WM_MOUSEHOVER, sent|wparam, 0 },
9480     { 0 }
9481 };
9482
9483 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
9484 {
9485     MSG msg;
9486     DWORD start_ticks, end_ticks;
9487
9488     start_ticks = GetTickCount();
9489     /* add some deviation (50%) to cover not expected delays */
9490     start_ticks += timeout / 2;
9491
9492     do
9493     {
9494         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
9495         {
9496             /* Timer proc messages are not dispatched to the window proc,
9497              * and therefore not logged.
9498              */
9499             if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER)
9500             {
9501                 struct message s_msg;
9502
9503                 s_msg.message = msg.message;
9504                 s_msg.flags = sent|wparam|lparam;
9505                 s_msg.wParam = msg.wParam;
9506                 s_msg.lParam = msg.lParam;
9507                 add_message(&s_msg);
9508             }
9509             DispatchMessage(&msg);
9510         }
9511
9512         end_ticks = GetTickCount();
9513
9514         /* inject WM_MOUSEMOVE to see how it changes tracking */
9515         if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
9516         {
9517             mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9518             mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9519
9520             inject_mouse_move = FALSE;
9521         }
9522     } while (start_ticks + timeout >= end_ticks);
9523 }
9524
9525 static void test_TrackMouseEvent(void)
9526 {
9527     TRACKMOUSEEVENT tme;
9528     BOOL ret;
9529     HWND hwnd, hchild;
9530     RECT rc_parent, rc_child;
9531     UINT default_hover_time, hover_width = 0, hover_height = 0;
9532
9533 #define track_hover(track_hwnd, track_hover_time) \
9534     tme.cbSize = sizeof(tme); \
9535     tme.dwFlags = TME_HOVER; \
9536     tme.hwndTrack = track_hwnd; \
9537     tme.dwHoverTime = track_hover_time; \
9538     SetLastError(0xdeadbeef); \
9539     ret = pTrackMouseEvent(&tme); \
9540     ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
9541
9542 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
9543     tme.cbSize = sizeof(tme); \
9544     tme.dwFlags = TME_QUERY; \
9545     tme.hwndTrack = (HWND)0xdeadbeef; \
9546     tme.dwHoverTime = 0xdeadbeef; \
9547     SetLastError(0xdeadbeef); \
9548     ret = pTrackMouseEvent(&tme); \
9549     ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
9550     ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
9551     ok(tme.dwFlags == (expected_track_flags), \
9552        "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
9553     ok(tme.hwndTrack == (expected_track_hwnd), \
9554        "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
9555     ok(tme.dwHoverTime == (expected_hover_time), \
9556        "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
9557
9558 #define track_hover_cancel(track_hwnd) \
9559     tme.cbSize = sizeof(tme); \
9560     tme.dwFlags = TME_HOVER | TME_CANCEL; \
9561     tme.hwndTrack = track_hwnd; \
9562     tme.dwHoverTime = 0xdeadbeef; \
9563     SetLastError(0xdeadbeef); \
9564     ret = pTrackMouseEvent(&tme); \
9565     ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
9566
9567     default_hover_time = 0xdeadbeef;
9568     SetLastError(0xdeadbeef);
9569     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
9570     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9571        "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
9572     if (!ret) default_hover_time = 400;
9573     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
9574
9575     SetLastError(0xdeadbeef);
9576     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
9577     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9578        "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
9579     if (!ret) hover_width = 4;
9580     SetLastError(0xdeadbeef);
9581     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
9582     ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
9583        "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
9584     if (!ret) hover_height = 4;
9585     trace("hover rect is %u x %d\n", hover_width, hover_height);
9586
9587     hwnd = CreateWindowEx(0, "TestWindowClass", NULL,
9588                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
9589                           CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9590                           NULL, NULL, 0);
9591     assert(hwnd);
9592
9593     hchild = CreateWindowEx(0, "TestWindowClass", NULL,
9594                           WS_CHILD | WS_BORDER | WS_VISIBLE,
9595                           50, 50, 200, 200, hwnd,
9596                           NULL, NULL, 0);
9597     assert(hchild);
9598
9599     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
9600     flush_events();
9601     flush_sequence();
9602
9603     tme.cbSize = 0;
9604     tme.dwFlags = TME_QUERY;
9605     tme.hwndTrack = (HWND)0xdeadbeef;
9606     tme.dwHoverTime = 0xdeadbeef;
9607     SetLastError(0xdeadbeef);
9608     ret = pTrackMouseEvent(&tme);
9609     ok(!ret, "TrackMouseEvent should fail\n");
9610     ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
9611        "not expected error %u\n", GetLastError());
9612
9613     tme.cbSize = sizeof(tme);
9614     tme.dwFlags = TME_HOVER;
9615     tme.hwndTrack = (HWND)0xdeadbeef;
9616     tme.dwHoverTime = 0xdeadbeef;
9617     SetLastError(0xdeadbeef);
9618     ret = pTrackMouseEvent(&tme);
9619     ok(!ret, "TrackMouseEvent should fail\n");
9620     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9621        "not expected error %u\n", GetLastError());
9622
9623     tme.cbSize = sizeof(tme);
9624     tme.dwFlags = TME_HOVER | TME_CANCEL;
9625     tme.hwndTrack = (HWND)0xdeadbeef;
9626     tme.dwHoverTime = 0xdeadbeef;
9627     SetLastError(0xdeadbeef);
9628     ret = pTrackMouseEvent(&tme);
9629     ok(!ret, "TrackMouseEvent should fail\n");
9630     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
9631        "not expected error %u\n", GetLastError());
9632
9633     GetWindowRect(hwnd, &rc_parent);
9634     GetWindowRect(hchild, &rc_child);
9635     SetCursorPos(rc_child.left - 10, rc_child.top - 10);
9636
9637     /* Process messages so that the system updates its internal current
9638      * window and hittest, otherwise TrackMouseEvent calls don't have any
9639      * effect.
9640      */
9641     flush_events();
9642     flush_sequence();
9643
9644     track_query(0, NULL, 0);
9645     track_hover(hchild, 0);
9646     track_query(0, NULL, 0);
9647
9648     flush_events();
9649     flush_sequence();
9650
9651     track_hover(hwnd, 0);
9652     track_query(TME_HOVER, hwnd, default_hover_time);
9653
9654     pump_msg_loop_timeout(default_hover_time, FALSE);
9655     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9656
9657     track_query(0, NULL, 0);
9658
9659     track_hover(hwnd, HOVER_DEFAULT);
9660     track_query(TME_HOVER, hwnd, default_hover_time);
9661
9662     Sleep(default_hover_time / 2);
9663     mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
9664     mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
9665
9666     track_query(TME_HOVER, hwnd, default_hover_time);
9667
9668     pump_msg_loop_timeout(default_hover_time / 2, FALSE);
9669     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9670
9671     track_query(0, NULL, 0);
9672
9673     track_hover(hwnd, HOVER_DEFAULT);
9674     track_query(TME_HOVER, hwnd, default_hover_time);
9675
9676     pump_msg_loop_timeout(default_hover_time, TRUE);
9677     ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
9678
9679     track_query(0, NULL, 0);
9680
9681     track_hover(hwnd, HOVER_DEFAULT);
9682     track_query(TME_HOVER, hwnd, default_hover_time);
9683     track_hover_cancel(hwnd);
9684
9685     DestroyWindow(hwnd);
9686
9687 #undef track_hover
9688 #undef track_query
9689 #undef track_hover_cancel
9690 }
9691
9692
9693 static const struct message WmSetWindowRgn[] = {
9694     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9695     { WM_NCCALCSIZE, sent|wparam, 1 },
9696     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
9697     { WM_GETTEXT, sent|defwinproc|optional },
9698     { WM_ERASEBKGND, sent|optional },
9699     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9700     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9701     { 0 }
9702 };
9703
9704 static const struct message WmSetWindowRgn_no_redraw[] = {
9705     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9706     { WM_NCCALCSIZE, sent|wparam, 1 },
9707     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
9708     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9709     { 0 }
9710 };
9711
9712 static const struct message WmSetWindowRgn_clear[] = {
9713     { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
9714     { WM_NCCALCSIZE, sent|wparam, 1 },
9715     { WM_NCPAINT, sent|optional },
9716     { WM_GETTEXT, sent|defwinproc|optional },
9717     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
9718     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9719     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
9720     { WM_NCPAINT, sent|optional },
9721     { WM_GETTEXT, sent|defwinproc|optional },
9722     { WM_ERASEBKGND, sent|optional },
9723     { WM_WINDOWPOSCHANGING, sent|optional },
9724     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9725     { WM_NCPAINT, sent|optional },
9726     { WM_GETTEXT, sent|defwinproc|optional },
9727     { WM_ERASEBKGND, sent|optional },
9728     { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
9729     { WM_NCCALCSIZE, sent|optional|wparam, 1 },
9730     { WM_NCPAINT, sent|optional },
9731     { WM_GETTEXT, sent|defwinproc|optional },
9732     { WM_ERASEBKGND, sent|optional },
9733     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9734     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
9735     { 0 }
9736 };
9737
9738 static void test_SetWindowRgn(void)
9739 {
9740     HRGN hrgn;
9741     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
9742                                 100, 100, 200, 200, 0, 0, 0, NULL);
9743     ok( hwnd != 0, "Failed to create overlapped window\n" );
9744
9745     ShowWindow( hwnd, SW_SHOW );
9746     UpdateWindow( hwnd );
9747     flush_events();
9748     flush_sequence();
9749
9750     trace("testing SetWindowRgn\n");
9751     hrgn = CreateRectRgn( 0, 0, 150, 150 );
9752     SetWindowRgn( hwnd, hrgn, TRUE );
9753     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
9754
9755     hrgn = CreateRectRgn( 30, 30, 160, 160 );
9756     SetWindowRgn( hwnd, hrgn, FALSE );
9757     ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
9758
9759     hrgn = CreateRectRgn( 0, 0, 180, 180 );
9760     SetWindowRgn( hwnd, hrgn, TRUE );
9761     ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
9762
9763     SetWindowRgn( hwnd, 0, TRUE );
9764     ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
9765
9766     DestroyWindow( hwnd );
9767 }
9768
9769 /*************************** ShowWindow() test ******************************/
9770 static const struct message WmShowNormal[] = {
9771     { WM_SHOWWINDOW, sent|wparam, 1 },
9772     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9773     { HCBT_ACTIVATE, hook },
9774     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9775     { HCBT_SETFOCUS, hook },
9776     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9777     { 0 }
9778 };
9779 static const struct message WmShow[] = {
9780     { WM_SHOWWINDOW, sent|wparam, 1 },
9781     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9782     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9783     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9784     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9785     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9786     { 0 }
9787 };
9788 static const struct message WmShowNoActivate_1[] = {
9789     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9790     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9791     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
9792     { WM_MOVE, sent|defwinproc },
9793     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9794     { 0 }
9795 };
9796 static const struct message WmShowNoActivate_2[] = {
9797     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
9798     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9799     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9800     { WM_MOVE, sent|defwinproc },
9801     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9802     { HCBT_SETFOCUS, hook|optional },
9803     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9804     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9805     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9806     { 0 }
9807 };
9808 static const struct message WmShowNA_1[] = {
9809     { WM_SHOWWINDOW, sent|wparam, 1 },
9810     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9811     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9812     { 0 }
9813 };
9814 static const struct message WmShowNA_2[] = {
9815     { WM_SHOWWINDOW, sent|wparam, 1 },
9816     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9817     { 0 }
9818 };
9819 static const struct message WmRestore_1[] = {
9820     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9821     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9822     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9823     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9824     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9825     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9826     { WM_MOVE, sent|defwinproc },
9827     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9828     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9829     { 0 }
9830 };
9831 static const struct message WmRestore_2[] = {
9832     { WM_SHOWWINDOW, sent|wparam, 1 },
9833     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9834     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9835     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9836     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9837     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9838     { 0 }
9839 };
9840 static const struct message WmRestore_3[] = {
9841     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9842     { WM_GETMINMAXINFO, sent },
9843     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9844     { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
9845     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
9846     { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
9847     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9848     { WM_MOVE, sent|defwinproc },
9849     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9850     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9851     { 0 }
9852 };
9853 static const struct message WmRestore_4[] = {
9854     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
9855     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9856     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9857     { WM_MOVE, sent|defwinproc },
9858     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9859     { 0 }
9860 };
9861 static const struct message WmRestore_5[] = {
9862     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
9863     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9864     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9865     { WM_MOVE, sent|defwinproc },
9866     { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
9867     { 0 }
9868 };
9869 static const struct message WmHide_1[] = {
9870     { WM_SHOWWINDOW, sent|wparam, 0 },
9871     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9872     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9873     { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
9874     { 0 }
9875 };
9876 static const struct message WmHide_2[] = {
9877     { WM_SHOWWINDOW, sent|wparam, 0 },
9878     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9879     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
9880     { 0 }
9881 };
9882 static const struct message WmHide_3[] = {
9883     { WM_SHOWWINDOW, sent|wparam, 0 },
9884     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
9885     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9886     { HCBT_SETFOCUS, hook|optional },
9887     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9888     { 0 }
9889 };
9890 static const struct message WmShowMinimized_1[] = {
9891     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9892     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9893     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9894     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9895     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9896     { WM_MOVE, sent|defwinproc },
9897     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9898     { 0 }
9899 };
9900 static const struct message WmMinimize_1[] = {
9901     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9902     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9903     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
9904     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9905     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9906     { WM_MOVE, sent|defwinproc },
9907     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9908     { 0 }
9909 };
9910 static const struct message WmMinimize_2[] = {
9911     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9912     { HCBT_SETFOCUS, hook|optional },
9913     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9914     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9915     { WM_MOVE, sent|defwinproc },
9916     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9917     { 0 }
9918 };
9919 static const struct message WmMinimize_3[] = {
9920     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9921     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9922     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9923     { WM_MOVE, sent|defwinproc },
9924     { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED },
9925     { 0 }
9926 };
9927 static const struct message WmShowMinNoActivate[] = {
9928     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9929     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
9930     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
9931     { 0 }
9932 };
9933 static const struct message WmMinMax_1[] = {
9934     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
9935     { 0 }
9936 };
9937 static const struct message WmMinMax_2[] = {
9938     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9939     { 0 }
9940 };
9941 static const struct message WmMinMax_3[] = {
9942     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
9943     { 0 }
9944 };
9945 static const struct message WmMinMax_4[] = {
9946     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
9947     { 0 }
9948 };
9949 static const struct message WmShowMaximized_1[] = {
9950     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9951     { WM_GETMINMAXINFO, sent },
9952     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9953     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9954     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9955     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9956     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9957     { WM_MOVE, sent|defwinproc },
9958     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9959     { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
9960     { 0 }
9961 };
9962 static const struct message WmShowMaximized_2[] = {
9963     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9964     { WM_GETMINMAXINFO, sent },
9965     { WM_WINDOWPOSCHANGING, sent|optional },
9966     { HCBT_ACTIVATE, hook|optional },
9967     { WM_WINDOWPOSCHANGED, sent|optional },
9968     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
9969     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
9970     { WM_WINDOWPOSCHANGING, sent },
9971     { HCBT_SETFOCUS, hook|optional },
9972     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
9973     { WM_MOVE, sent|defwinproc },
9974     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9975     { HCBT_SETFOCUS, hook|optional },
9976     { 0 }
9977 };
9978 static const struct message WmShowMaximized_3[] = {
9979     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
9980     { WM_GETMINMAXINFO, sent },
9981     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9982     { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
9983     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
9984     { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
9985     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
9986     { WM_MOVE, sent|defwinproc },
9987     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
9988     { 0 }
9989 };
9990
9991 static void test_ShowWindow(void)
9992 {
9993     /* ShowWindow commands in random order */
9994     static const struct
9995     {
9996         INT cmd; /* ShowWindow command */
9997         LPARAM ret; /* ShowWindow return value */
9998         DWORD style; /* window style after the command */
9999         const struct message *msg; /* message sequence the command produces */
10000         BOOL todo_msg; /* message sequence doesn't match what Wine does */
10001     } sw[] =
10002     {
10003 /*  1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal, FALSE },
10004 /*  2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10005 /*  3 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10006 /*  4 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10007 /*  5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1, FALSE },
10008 /*  6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1, FALSE },
10009 /*  7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1, FALSE },
10010 /*  8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10011 /*  9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1, FALSE },
10012 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10013 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1, FALSE },
10014 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq, FALSE },
10015 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1, FALSE },
10016 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10017 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2, FALSE },
10018 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10019 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow, FALSE },
10020 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10021 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10022 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10023 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10024 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate, TRUE },
10025 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4, FALSE },
10026 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10027 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10028 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1, FALSE },
10029 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2, FALSE },
10030 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10031 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
10032 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
10033 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10034 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
10035 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10036 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
10037 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
10038 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10039 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2, FALSE },
10040 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10041 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10042 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE },
10043 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10044 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE },
10045 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE },
10046 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE },
10047 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE },
10048 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3, FALSE },
10049 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4, FALSE },
10050 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE },
10051 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE },
10052 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE },
10053 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
10054 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE },
10055 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
10056 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE },
10057 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2, FALSE },
10058 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2, FALSE },
10059 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }
10060     };
10061     HWND hwnd;
10062     DWORD style;
10063     LPARAM ret;
10064     INT i;
10065
10066 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
10067     hwnd = CreateWindowEx(0, "ShowWindowClass", NULL, WS_BASE,
10068                           120, 120, 90, 90,
10069                           0, 0, 0, NULL);
10070     assert(hwnd);
10071
10072     style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10073     ok(style == 0, "expected style 0, got %08x\n", style);
10074
10075     flush_events();
10076     flush_sequence();
10077
10078     for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
10079     {
10080         static const char * const sw_cmd_name[13] =
10081         {
10082             "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
10083             "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
10084             "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
10085             "SW_NORMALNA" /* 0xCC */
10086         };
10087         char comment[64];
10088         INT idx; /* index into the above array of names */
10089
10090         idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
10091
10092         style = GetWindowLong(hwnd, GWL_STYLE);
10093         trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
10094         ret = ShowWindow(hwnd, sw[i].cmd);
10095         ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
10096         style = GetWindowLong(hwnd, GWL_STYLE) & ~WS_BASE;
10097         ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
10098
10099         sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
10100         ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
10101
10102         flush_events();
10103         flush_sequence();
10104     }
10105
10106     DestroyWindow(hwnd);
10107 }
10108
10109 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10110 {
10111     struct message msg;
10112
10113     trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
10114
10115     switch (message)
10116     {
10117     case WM_WINDOWPOSCHANGING:
10118     case WM_WINDOWPOSCHANGED:
10119     {
10120         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
10121
10122         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
10123         trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
10124               winpos->hwnd, winpos->hwndInsertAfter,
10125               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
10126         dump_winpos_flags(winpos->flags);
10127
10128         /* Log only documented flags, win2k uses 0x1000 and 0x2000
10129          * in the high word for internal purposes
10130          */
10131         wParam = winpos->flags & 0xffff;
10132         /* We are not interested in the flags that don't match under XP and Win9x */
10133         wParam &= ~(SWP_NOZORDER);
10134         break;
10135     }
10136
10137     /* explicitly ignore WM_GETICON message */
10138     case WM_GETICON:
10139         return 0;
10140     }
10141
10142     msg.message = message;
10143     msg.flags = sent|wparam|lparam;
10144     msg.wParam = wParam;
10145     msg.lParam = lParam;
10146     add_message(&msg);
10147
10148     /* calling DefDlgProc leads to a recursion under XP */
10149
10150     switch (message)
10151     {
10152     case WM_INITDIALOG:
10153     case WM_GETDLGCODE:
10154         return 0;
10155     }
10156     return 1;
10157 }
10158
10159 static const struct message WmDefDlgSetFocus_1[] = {
10160     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10161     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10162     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10163     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10164     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10165     { HCBT_SETFOCUS, hook },
10166     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
10167     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10168     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10169     { WM_SETFOCUS, sent|wparam, 0 },
10170     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
10171     { WM_CTLCOLOREDIT, sent },
10172     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
10173     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10174     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10175     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10176     { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
10177     { 0 }
10178 };
10179 static const struct message WmDefDlgSetFocus_2[] = {
10180     { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
10181     { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
10182     { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
10183     { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
10184     { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
10185     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10186     { WM_CTLCOLOREDIT, sent|optional }, /* XP */
10187     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
10188     { 0 }
10189 };
10190 /* Creation of a dialog */
10191 static const struct message WmCreateDialogParamSeq_1[] = {
10192     { HCBT_CREATEWND, hook },
10193     { WM_NCCREATE, sent },
10194     { WM_NCCALCSIZE, sent|wparam, 0 },
10195     { WM_CREATE, sent },
10196     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10197     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10198     { WM_MOVE, sent },
10199     { WM_SETFONT, sent },
10200     { WM_INITDIALOG, sent },
10201     { WM_CHANGEUISTATE, sent|optional },
10202     { 0 }
10203 };
10204 /* Creation of a dialog */
10205 static const struct message WmCreateDialogParamSeq_2[] = {
10206     { HCBT_CREATEWND, hook },
10207     { WM_NCCREATE, sent },
10208     { WM_NCCALCSIZE, sent|wparam, 0 },
10209     { WM_CREATE, sent },
10210     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
10211     { WM_SIZE, sent|wparam, SIZE_RESTORED },
10212     { WM_MOVE, sent },
10213     { WM_CHANGEUISTATE, sent|optional },
10214     { 0 }
10215 };
10216
10217 static void test_dialog_messages(void)
10218 {
10219     WNDCLASS cls;
10220     HWND hdlg, hedit1, hedit2, hfocus;
10221     LRESULT ret;
10222
10223 #define set_selection(hctl, start, end) \
10224     ret = SendMessage(hctl, EM_SETSEL, start, end); \
10225     ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
10226
10227 #define check_selection(hctl, start, end) \
10228     ret = SendMessage(hctl, EM_GETSEL, 0, 0); \
10229     ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
10230
10231     subclass_edit();
10232
10233     hdlg = CreateWindowEx(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
10234                           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
10235                           0, 0, 100, 100, 0, 0, 0, NULL);
10236     ok(hdlg != 0, "Failed to create custom dialog window\n");
10237
10238     hedit1 = CreateWindowEx(0, "my_edit_class", NULL,
10239                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10240                            0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
10241     ok(hedit1 != 0, "Failed to create edit control\n");
10242     hedit2 = CreateWindowEx(0, "my_edit_class", NULL,
10243                            WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
10244                            0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
10245     ok(hedit2 != 0, "Failed to create edit control\n");
10246
10247     SendMessage(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
10248     SendMessage(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
10249
10250     hfocus = GetFocus();
10251     ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
10252
10253     SetFocus(hedit2);
10254     hfocus = GetFocus();
10255     ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
10256
10257     check_selection(hedit1, 0, 0);
10258     check_selection(hedit2, 0, 0);
10259
10260     set_selection(hedit2, 0, -1);
10261     check_selection(hedit2, 0, 3);
10262
10263     SetFocus(0);
10264     hfocus = GetFocus();
10265     ok(hfocus == 0, "wrong focus %p\n", hfocus);
10266
10267     flush_sequence();
10268     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10269     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10270     ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
10271
10272     hfocus = GetFocus();
10273     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10274
10275     check_selection(hedit1, 0, 5);
10276     check_selection(hedit2, 0, 3);
10277
10278     flush_sequence();
10279     ret = DefDlgProc(hdlg, WM_SETFOCUS, 0, 0);
10280     ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
10281     ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
10282
10283     hfocus = GetFocus();
10284     ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
10285
10286     check_selection(hedit1, 0, 5);
10287     check_selection(hedit2, 0, 3);
10288
10289     EndDialog(hdlg, 0);
10290     DestroyWindow(hedit1);
10291     DestroyWindow(hedit2);
10292     DestroyWindow(hdlg);
10293     flush_sequence();
10294
10295 #undef set_selection
10296 #undef check_selection
10297
10298     ok(GetClassInfo(0, "#32770", &cls), "GetClassInfo failed\n");
10299     cls.lpszClassName = "MyDialogClass";
10300     cls.hInstance = GetModuleHandle(0);
10301     /* need a cast since a dlgproc is used as a wndproc */
10302     cls.lpfnWndProc = (WNDPROC)test_dlg_proc;
10303     if (!RegisterClass(&cls)) assert(0);
10304
10305     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
10306     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10307     ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
10308     EndDialog(hdlg, 0);
10309     DestroyWindow(hdlg);
10310     flush_sequence();
10311
10312     hdlg = CreateDialogParam(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
10313     ok(IsWindow(hdlg), "CreateDialogParam failed\n");
10314     ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
10315     EndDialog(hdlg, 0);
10316     DestroyWindow(hdlg);
10317     flush_sequence();
10318
10319     UnregisterClass(cls.lpszClassName, cls.hInstance);
10320 }
10321
10322 static void test_nullCallback(void)
10323 {
10324     HWND hwnd;
10325
10326     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
10327                            100, 100, 200, 200, 0, 0, 0, NULL);
10328     ok (hwnd != 0, "Failed to create overlapped window\n");
10329
10330     SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
10331     flush_events();
10332     DestroyWindow(hwnd);
10333 }
10334
10335 /* SetActiveWindow( 0 ) hwnd visible */
10336 static const struct message SetActiveWindowSeq0[] =
10337 {
10338     { HCBT_ACTIVATE, hook },
10339     { WM_NCACTIVATE, sent|wparam, 0 },
10340     { WM_GETTEXT, sent|defwinproc|optional },
10341     { WM_ACTIVATE, sent|wparam, 0 },
10342     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10343     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10344     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10345     { WM_NCACTIVATE, sent|wparam, 1 },
10346     { WM_GETTEXT, sent|defwinproc|optional },
10347     { WM_ACTIVATE, sent|wparam, 1 },
10348     { HCBT_SETFOCUS, hook },
10349     { WM_KILLFOCUS, sent|defwinproc },
10350     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10351     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10352     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10353     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10354     { WM_SETFOCUS, sent|defwinproc },
10355     { WM_GETTEXT, sent|optional },
10356     { 0 }
10357 };
10358 /* SetActiveWindow( hwnd ) hwnd visible */
10359 static const struct message SetActiveWindowSeq1[] =
10360 {
10361     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10362     { 0 }
10363 };
10364 /* SetActiveWindow( popup ) hwnd visible, popup visible */
10365 static const struct message SetActiveWindowSeq2[] =
10366 {
10367     { HCBT_ACTIVATE, hook },
10368     { WM_NCACTIVATE, sent|wparam, 0 },
10369     { WM_GETTEXT, sent|defwinproc|optional },
10370     { WM_ACTIVATE, sent|wparam, 0 },
10371     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10372     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
10373     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10374     { WM_NCPAINT, sent|optional },
10375     { WM_GETTEXT, sent|defwinproc|optional },
10376     { WM_ERASEBKGND, sent|optional },
10377     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10378     { WM_NCACTIVATE, sent|wparam, 1 },
10379     { WM_GETTEXT, sent|defwinproc|optional },
10380     { WM_ACTIVATE, sent|wparam, 1 },
10381     { HCBT_SETFOCUS, hook },
10382     { WM_KILLFOCUS, sent|defwinproc },
10383     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10384     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10385     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10386     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10387     { WM_SETFOCUS, sent|defwinproc },
10388     { WM_GETTEXT, sent|optional },
10389     { 0 }
10390 };
10391
10392 /* SetActiveWindow( hwnd ) hwnd not visible */
10393 static const struct message SetActiveWindowSeq3[] =
10394 {
10395     { HCBT_ACTIVATE, hook },
10396     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10397     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10398     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10399     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10400     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10401     { WM_ACTIVATEAPP, sent|wparam, 1 },
10402     { WM_ACTIVATEAPP, sent|wparam, 1 },
10403     { WM_NCACTIVATE, sent|wparam, 1 },
10404     { WM_ACTIVATE, sent|wparam, 1 },
10405     { HCBT_SETFOCUS, hook },
10406     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10407     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10408     { WM_SETFOCUS, sent|defwinproc },
10409     { 0 }
10410 };
10411 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
10412 static const struct message SetActiveWindowSeq4[] =
10413 {
10414     { HCBT_ACTIVATE, hook },
10415     { WM_NCACTIVATE, sent|wparam, 0 },
10416     { WM_GETTEXT, sent|defwinproc|optional },
10417     { WM_ACTIVATE, sent|wparam, 0 },
10418     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
10419     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
10420     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
10421     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
10422     { WM_NCACTIVATE, sent|wparam, 1 },
10423     { WM_GETTEXT, sent|defwinproc|optional },
10424     { WM_ACTIVATE, sent|wparam, 1 },
10425     { HCBT_SETFOCUS, hook },
10426     { WM_KILLFOCUS, sent|defwinproc },
10427     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
10428     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10429     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
10430     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
10431     { WM_SETFOCUS, sent|defwinproc },
10432     { 0 }
10433 };
10434
10435
10436 static void test_SetActiveWindow(void)
10437 {
10438     HWND hwnd, popup, ret;
10439
10440     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10441                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10442                            100, 100, 200, 200, 0, 0, 0, NULL);
10443
10444     popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
10445                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
10446                            100, 100, 200, 200, hwnd, 0, 0, NULL);
10447
10448     ok(hwnd != 0, "Failed to create overlapped window\n");
10449     flush_sequence();
10450
10451     ok(popup != 0, "Failed to create popup window\n");
10452     flush_sequence();
10453
10454     trace("SetActiveWindow(0)\n");
10455     ret = SetActiveWindow(0);
10456     ok( ret == popup, "Failed to SetActiveWindow(0)\n");
10457     ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", TRUE);
10458     flush_sequence();
10459
10460     trace("SetActiveWindow(hwnd), hwnd visible\n");
10461     ret = SetActiveWindow(hwnd);
10462     todo_wine
10463     {
10464         ok( ret == hwnd, "Failed to SetActiveWindow(hwnd), hwnd visible\n");
10465     }
10466     ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
10467     flush_sequence();
10468
10469     trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
10470     ret = SetActiveWindow(popup);
10471     ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
10472     ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
10473     flush_sequence();
10474
10475     ShowWindow(hwnd, SW_HIDE);
10476     ShowWindow(popup, SW_HIDE);
10477     flush_sequence();
10478
10479     trace("SetActiveWindow(hwnd), hwnd not visible\n");
10480     ret = SetActiveWindow(hwnd);
10481     ok( ret == NULL, "Failed to SetActiveWindow(hwnd), hwnd not visible\n");
10482     ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
10483     flush_sequence();
10484
10485     trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
10486     ret = SetActiveWindow(popup);
10487     ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
10488     ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
10489     flush_sequence();
10490
10491     trace("done\n");
10492
10493     DestroyWindow(hwnd);
10494 }
10495
10496 static const struct message SetForegroundWindowSeq[] =
10497 {
10498     { WM_NCACTIVATE, sent|wparam, 0 },
10499     { WM_GETTEXT, sent|defwinproc|optional },
10500     { WM_ACTIVATE, sent|wparam, 0 },
10501     { WM_ACTIVATEAPP, sent|wparam, 0 },
10502     { WM_KILLFOCUS, sent },
10503     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
10504     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
10505     { 0 }
10506 };
10507
10508 static void test_SetForegroundWindow(void)
10509 {
10510     HWND hwnd;
10511
10512     hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
10513                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10514                            100, 100, 200, 200, 0, 0, 0, NULL);
10515     ok (hwnd != 0, "Failed to create overlapped window\n");
10516     flush_sequence();
10517
10518     trace("SetForegroundWindow( 0 )\n");
10519     SetForegroundWindow( 0 );
10520     ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
10521     trace("SetForegroundWindow( GetDesktopWindow() )\n");
10522     SetForegroundWindow( GetDesktopWindow() );
10523     ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
10524                                         "foreground top level window", FALSE);
10525     trace("done\n");
10526
10527     DestroyWindow(hwnd);
10528 }
10529
10530 static void test_dbcs_wm_char(void)
10531 {
10532     BYTE dbch[2];
10533     WCHAR wch, bad_wch;
10534     HWND hwnd, hwnd2;
10535     MSG msg;
10536     DWORD time;
10537     POINT pt;
10538     DWORD_PTR res;
10539     CPINFOEXA cpinfo;
10540     UINT i, j, k;
10541     struct message wmCharSeq[2];
10542
10543     if (!pGetCPInfoExA)
10544     {
10545         skip("GetCPInfoExA is not available\n");
10546         return;
10547     }
10548
10549     pGetCPInfoExA( CP_ACP, 0, &cpinfo );
10550     if (cpinfo.MaxCharSize != 2)
10551     {
10552         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
10553         return;
10554     }
10555
10556     dbch[0] = dbch[1] = 0;
10557     wch = 0;
10558     bad_wch = cpinfo.UnicodeDefaultChar;
10559     for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
10560         for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
10561             for (k = 128; k <= 255; k++)
10562             {
10563                 char str[2];
10564                 WCHAR wstr[2];
10565                 str[0] = j;
10566                 str[1] = k;
10567                 if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
10568                     WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
10569                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
10570                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
10571                 {
10572                     dbch[0] = j;
10573                     dbch[1] = k;
10574                     wch = wstr[0];
10575                     break;
10576                 }
10577             }
10578
10579     if (!wch)
10580     {
10581         skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
10582         return;
10583     }
10584     trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
10585            dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
10586
10587     hwnd = CreateWindowExW(0, testWindowClassW, NULL,
10588                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10589     hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
10590                            WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
10591     ok (hwnd != 0, "Failed to create overlapped window\n");
10592     ok (hwnd2 != 0, "Failed to create overlapped window\n");
10593     flush_sequence();
10594
10595     memset( wmCharSeq, 0, sizeof(wmCharSeq) );
10596     wmCharSeq[0].message = WM_CHAR;
10597     wmCharSeq[0].flags = sent|wparam;
10598     wmCharSeq[0].wParam = wch;
10599
10600     /* posted message */
10601     PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10602     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10603     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10604     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10605     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10606     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10607     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10608
10609     /* posted thread message */
10610     PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
10611     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10612     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10613     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10614     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10615     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10616     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10617
10618     /* sent message */
10619     flush_sequence();
10620     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10621     ok_sequence( WmEmptySeq, "no messages", FALSE );
10622     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10623     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10624     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10625
10626     /* sent message with timeout */
10627     flush_sequence();
10628     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10629     ok_sequence( WmEmptySeq, "no messages", FALSE );
10630     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10631     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10632     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10633
10634     /* sent message with timeout and callback */
10635     flush_sequence();
10636     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
10637     ok_sequence( WmEmptySeq, "no messages", FALSE );
10638     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10639     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10640     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10641
10642     /* sent message with callback */
10643     flush_sequence();
10644     SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10645     ok_sequence( WmEmptySeq, "no messages", FALSE );
10646     SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
10647     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10648     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10649
10650     /* direct window proc call */
10651     flush_sequence();
10652     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10653     ok_sequence( WmEmptySeq, "no messages", FALSE );
10654     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10655     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10656
10657     /* dispatch message */
10658     msg.hwnd = hwnd;
10659     msg.message = WM_CHAR;
10660     msg.wParam = dbch[0];
10661     msg.lParam = 0;
10662     DispatchMessageA( &msg );
10663     ok_sequence( WmEmptySeq, "no messages", FALSE );
10664     msg.wParam = dbch[1];
10665     DispatchMessageA( &msg );
10666     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10667
10668     /* window handle is irrelevant */
10669     flush_sequence();
10670     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10671     ok_sequence( WmEmptySeq, "no messages", FALSE );
10672     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10673     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10674     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10675
10676     /* interleaved post and send */
10677     flush_sequence();
10678     PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10679     SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
10680     ok_sequence( WmEmptySeq, "no messages", FALSE );
10681     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10682     PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10683     ok_sequence( WmEmptySeq, "no messages", FALSE );
10684     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10685     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10686     ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
10687     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10688     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10689     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10690     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10691
10692     /* interleaved sent message and winproc */
10693     flush_sequence();
10694     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10695     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10696     ok_sequence( WmEmptySeq, "no messages", FALSE );
10697     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10698     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10699     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10700     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10701
10702     /* interleaved winproc and dispatch */
10703     msg.hwnd = hwnd;
10704     msg.message = WM_CHAR;
10705     msg.wParam = dbch[0];
10706     msg.lParam = 0;
10707     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
10708     DispatchMessageA( &msg );
10709     ok_sequence( WmEmptySeq, "no messages", FALSE );
10710     msg.wParam = dbch[1];
10711     DispatchMessageA( &msg );
10712     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10713     CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
10714     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10715
10716     /* interleaved sends */
10717     flush_sequence();
10718     SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
10719     SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
10720     ok_sequence( WmEmptySeq, "no messages", FALSE );
10721     SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
10722     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10723     SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
10724     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10725
10726     /* dbcs WM_CHAR */
10727     flush_sequence();
10728     SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
10729     ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
10730     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10731
10732     /* other char messages are not magic */
10733     PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
10734     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10735     ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
10736     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10737     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10738     PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
10739     ok( PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10740     ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
10741     ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
10742     ok( !PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10743
10744     /* test retrieving messages */
10745
10746     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10747     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10748     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10749     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10750     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10751     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10752     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10753     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10754     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10755     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10756
10757     /* message filters */
10758     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10759     ok( PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "no message\n" );
10760     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10761     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10762     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10763     /* message id is filtered, hwnd is not */
10764     ok( !PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ), "no message\n" );
10765     ok( PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE ), "no message\n" );
10766     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10767     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10768     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10769     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10770
10771     /* mixing GetMessage and PostMessage */
10772     PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
10773     ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
10774     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10775     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10776     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10777     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10778     time = msg.time;
10779     pt = msg.pt;
10780     ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
10781     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10782     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10783     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10784     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10785     ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
10786     ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
10787     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 );
10788     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10789
10790     /* without PM_REMOVE */
10791     PostMessageW( hwnd, WM_CHAR, wch, 0 );
10792     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10793     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10794     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10795     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10796     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10797     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10798     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10799     ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10800     ok( PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "no message\n" );
10801     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10802     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10803     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10804     ok( PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "no message\n" );
10805     ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
10806     ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
10807     ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
10808     ok( !PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "got message %x\n", msg.message );
10809
10810     DestroyWindow(hwnd);
10811 }
10812
10813 #define ID_LISTBOX 0x000f
10814
10815 static const struct message wm_lb_setcursel_0[] =
10816 {
10817     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
10818     { WM_CTLCOLORLISTBOX, sent|parent },
10819     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10820     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10821     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10822     { 0 }
10823 };
10824 static const struct message wm_lb_setcursel_1[] =
10825 {
10826     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
10827     { WM_CTLCOLORLISTBOX, sent|parent },
10828     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
10829     { WM_CTLCOLORLISTBOX, sent|parent },
10830     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
10831     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10832     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
10833     { 0 }
10834 };
10835 static const struct message wm_lb_setcursel_2[] =
10836 {
10837     { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
10838     { WM_CTLCOLORLISTBOX, sent|parent },
10839     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
10840     { WM_CTLCOLORLISTBOX, sent|parent },
10841     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
10842     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10843     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10844     { 0 }
10845 };
10846 static const struct message wm_lb_click_0[] =
10847 {
10848     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
10849     { HCBT_SETFOCUS, hook },
10850     { WM_KILLFOCUS, sent|parent },
10851     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
10852     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
10853     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
10854     { WM_SETFOCUS, sent|defwinproc },
10855
10856     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
10857     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
10858     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
10859     { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
10860     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
10861
10862     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
10863     { WM_CTLCOLORLISTBOX, sent|parent },
10864     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
10865     { WM_CTLCOLORLISTBOX, sent|parent },
10866     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
10867     { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
10868
10869     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10870     { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
10871
10872     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
10873     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
10874     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
10875     { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
10876     { 0 }
10877 };
10878
10879 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
10880
10881 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
10882
10883 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
10884 {
10885     static long defwndproc_counter = 0;
10886     LRESULT ret;
10887     struct message msg;
10888
10889     /* do not log painting messages */
10890     if (message != WM_PAINT &&
10891         message != WM_NCPAINT &&
10892         message != WM_SYNCPAINT &&
10893         message != WM_ERASEBKGND &&
10894         message != WM_NCHITTEST &&
10895         message != WM_GETTEXT &&
10896         message != WM_GETICON &&
10897         message != WM_DEVICECHANGE)
10898     {
10899         trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
10900
10901         msg.message = message;
10902         msg.flags = sent|wparam|lparam;
10903         if (defwndproc_counter) msg.flags |= defwinproc;
10904         msg.wParam = wp;
10905         msg.lParam = lp;
10906         add_message(&msg);
10907     }
10908
10909     defwndproc_counter++;
10910     ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
10911     defwndproc_counter--;
10912
10913     return ret;
10914 }
10915
10916 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
10917                                int caret_index, int top_index, int line)
10918 {
10919     LRESULT ret;
10920
10921     /* calling an orig proc helps to avoid unnecessary message logging */
10922     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
10923     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
10924     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
10925     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
10926     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
10927     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
10928     ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
10929     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
10930 }
10931
10932 static void test_listbox_messages(void)
10933 {
10934     HWND parent, listbox;
10935     LRESULT ret;
10936
10937     parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW  | WS_VISIBLE,
10938                              100, 100, 200, 200, 0, 0, 0, NULL);
10939     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
10940                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10941                               10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
10942     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
10943
10944     check_lb_state(listbox, 0, LB_ERR, 0, 0);
10945
10946     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
10947     ok(ret == 0, "expected 0, got %ld\n", ret);
10948     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
10949     ok(ret == 1, "expected 1, got %ld\n", ret);
10950     ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
10951     ok(ret == 2, "expected 2, got %ld\n", ret);
10952
10953     check_lb_state(listbox, 3, LB_ERR, 0, 0);
10954
10955     flush_sequence();
10956
10957     log_all_parent_messages++;
10958
10959     trace("selecting item 0\n");
10960     ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
10961     ok(ret == 0, "expected 0, got %ld\n", ret);
10962     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
10963     check_lb_state(listbox, 3, 0, 0, 0);
10964     flush_sequence();
10965
10966     trace("selecting item 1\n");
10967     ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
10968     ok(ret == 1, "expected 1, got %ld\n", ret);
10969     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
10970     check_lb_state(listbox, 3, 1, 1, 0);
10971
10972     trace("selecting item 2\n");
10973     ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
10974     ok(ret == 2, "expected 2, got %ld\n", ret);
10975     ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
10976     check_lb_state(listbox, 3, 2, 2, 0);
10977
10978     trace("clicking on item 0\n");
10979     ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
10980     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10981     ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
10982     ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
10983     ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
10984     check_lb_state(listbox, 3, 0, 0, 0);
10985     flush_sequence();
10986
10987     log_all_parent_messages--;
10988
10989     DestroyWindow(listbox);
10990     DestroyWindow(parent);
10991 }
10992
10993 /*************************** Menu test ******************************/
10994 static const struct message wm_popup_menu_1[] =
10995 {
10996     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
10997     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
10998     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
10999     { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
11000     { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
11001     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
11002     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11003     { WM_INITMENU, sent|lparam, 0, 0 },
11004     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
11005     { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
11006     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
11007     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
11008     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
11009     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11010     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11011     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
11012     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11013     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11014     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11015     { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
11016     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11017     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11018     { 0 }
11019 };
11020 static const struct message wm_popup_menu_2[] =
11021 {
11022     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11023     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11024     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11025     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11026     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11027     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11028     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11029     { WM_INITMENU, sent|lparam, 0, 0 },
11030     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11031     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11032     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11033     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11034     { HCBT_CREATEWND, hook },
11035     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11036                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11037     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11038     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11039     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11040     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11041     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11042     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11043     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11044     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11045     { HCBT_DESTROYWND, hook },
11046     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11047     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11048     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11049     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11050     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11051     { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
11052     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11053     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11054     { 0 }
11055 };
11056 static const struct message wm_popup_menu_3[] =
11057 {
11058     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
11059     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
11060     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
11061     { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
11062     { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
11063     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
11064     { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
11065     { WM_INITMENU, sent|lparam, 0, 0 },
11066     { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
11067     { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
11068     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
11069     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
11070     { HCBT_CREATEWND, hook },
11071     { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
11072                                |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
11073     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
11074     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
11075     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
11076     { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
11077     { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
11078     { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
11079     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
11080     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
11081     { HCBT_DESTROYWND, hook },
11082     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11083     { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
11084     { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
11085     { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
11086     { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
11087     { WM_COMMAND, sent|wparam|lparam, 100, 0 },
11088     { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
11089     { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
11090     { 0 }
11091 };
11092
11093 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
11094 {
11095     if (message == WM_ENTERIDLE ||
11096         message == WM_INITMENU ||
11097         message == WM_INITMENUPOPUP ||
11098         message == WM_MENUSELECT ||
11099         message == WM_PARENTNOTIFY ||
11100         message == WM_ENTERMENULOOP ||
11101         message == WM_EXITMENULOOP ||
11102         message == WM_UNINITMENUPOPUP ||
11103         message == WM_KEYDOWN ||
11104         message == WM_KEYUP ||
11105         message == WM_CHAR ||
11106         message == WM_SYSKEYDOWN ||
11107         message == WM_SYSKEYUP ||
11108         message == WM_SYSCHAR ||
11109         message == WM_COMMAND ||
11110         message == WM_MENUCOMMAND)
11111     {
11112         struct message msg;
11113
11114         trace("parent_menu_proc: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
11115
11116         msg.message = message;
11117         msg.flags = sent|wparam|lparam;
11118         msg.wParam = wp;
11119         msg.lParam = lp;
11120         add_message(&msg);
11121     }
11122
11123     return DefWindowProcA(hwnd, message, wp, lp);
11124 }
11125
11126 static void set_menu_style(HMENU hmenu, DWORD style)
11127 {
11128     MENUINFO mi;
11129     BOOL ret;
11130
11131     mi.cbSize = sizeof(mi);
11132     mi.fMask = MIM_STYLE;
11133     mi.dwStyle = style;
11134     SetLastError(0xdeadbeef);
11135     ret = pSetMenuInfo(hmenu, &mi);
11136     ok(ret, "SetMenuInfo error %u\n", GetLastError());
11137 }
11138
11139 static DWORD get_menu_style(HMENU hmenu)
11140 {
11141     MENUINFO mi;
11142     BOOL ret;
11143
11144     mi.cbSize = sizeof(mi);
11145     mi.fMask = MIM_STYLE;
11146     mi.dwStyle = 0;
11147     SetLastError(0xdeadbeef);
11148     ret = pGetMenuInfo(hmenu, &mi);
11149     ok(ret, "GetMenuInfo error %u\n", GetLastError());
11150
11151     return mi.dwStyle;
11152 }
11153
11154 static void test_menu_messages(void)
11155 {
11156     MSG msg;
11157     WNDCLASSA cls;
11158     HMENU hmenu, hmenu_popup;
11159     HWND hwnd;
11160     DWORD style;
11161
11162     if (!pGetMenuInfo || !pSetMenuInfo)
11163     {
11164         skip("GetMenuInfo and/or SetMenuInfo are not available\n");
11165         return;
11166     }
11167     cls.style = 0;
11168     cls.lpfnWndProc = parent_menu_proc;
11169     cls.cbClsExtra = 0;
11170     cls.cbWndExtra = 0;
11171     cls.hInstance = GetModuleHandleA(0);
11172     cls.hIcon = 0;
11173     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
11174     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
11175     cls.lpszMenuName = NULL;
11176     cls.lpszClassName = "TestMenuClass";
11177     UnregisterClass(cls.lpszClassName, cls.hInstance);
11178     if (!RegisterClassA(&cls)) assert(0);
11179
11180     SetLastError(0xdeadbeef);
11181     hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11182                            100, 100, 200, 200, 0, 0, 0, NULL);
11183     ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
11184
11185     SetLastError(0xdeadbeef);
11186     hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
11187     ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
11188
11189     SetMenu(hwnd, hmenu);
11190     SetForegroundWindow( hwnd );
11191
11192     set_menu_style(hmenu, MNS_NOTIFYBYPOS);
11193     style = get_menu_style(hmenu);
11194     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11195
11196     hmenu_popup = GetSubMenu(hmenu, 0);
11197     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11198     style = get_menu_style(hmenu_popup);
11199     ok(style == 0, "expected 0, got %u\n", style);
11200
11201     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11202     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11203     style = get_menu_style(hmenu_popup);
11204     ok(style == 0, "expected 0, got %u\n", style);
11205
11206     /* Alt+E, Enter */
11207     trace("testing a popup menu command\n");
11208     flush_sequence();
11209     keybd_event(VK_MENU, 0, 0, 0);
11210     keybd_event('E', 0, 0, 0);
11211     keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
11212     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11213     keybd_event(VK_RETURN, 0, 0, 0);
11214     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11215     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11216     {
11217         TranslateMessage(&msg);
11218         DispatchMessage(&msg);
11219     }
11220     ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
11221
11222     /* Alt+F, Right, Enter */
11223     trace("testing submenu of a popup menu command\n");
11224     flush_sequence();
11225     keybd_event(VK_MENU, 0, 0, 0);
11226     keybd_event('F', 0, 0, 0);
11227     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11228     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11229     keybd_event(VK_RIGHT, 0, 0, 0);
11230     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11231     keybd_event(VK_RETURN, 0, 0, 0);
11232     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11233     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11234     {
11235         TranslateMessage(&msg);
11236         DispatchMessage(&msg);
11237     }
11238     ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
11239
11240     set_menu_style(hmenu, 0);
11241     style = get_menu_style(hmenu);
11242     ok(style == 0, "expected 0, got %u\n", style);
11243
11244     hmenu_popup = GetSubMenu(hmenu, 0);
11245     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11246     set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
11247     style = get_menu_style(hmenu_popup);
11248     ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
11249
11250     hmenu_popup = GetSubMenu(hmenu_popup, 0);
11251     ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
11252     style = get_menu_style(hmenu_popup);
11253     ok(style == 0, "expected 0, got %u\n", style);
11254
11255     /* Alt+F, Right, Enter */
11256     trace("testing submenu of a popup menu command\n");
11257     flush_sequence();
11258     keybd_event(VK_MENU, 0, 0, 0);
11259     keybd_event('F', 0, 0, 0);
11260     keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
11261     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
11262     keybd_event(VK_RIGHT, 0, 0, 0);
11263     keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
11264     keybd_event(VK_RETURN, 0, 0, 0);
11265     keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
11266     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
11267     {
11268         TranslateMessage(&msg);
11269         DispatchMessage(&msg);
11270     }
11271     ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
11272
11273     DestroyWindow(hwnd);
11274     DestroyMenu(hmenu);
11275 }
11276
11277
11278 static void test_paintingloop(void)
11279 {
11280     HWND hwnd;
11281
11282     paint_loop_done = 0;
11283     hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
11284                                "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
11285                                 100, 100, 100, 100, 0, 0, 0, NULL );
11286     ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
11287     ShowWindow(hwnd,SW_NORMAL);
11288     SetFocus(hwnd);
11289
11290     while (!paint_loop_done)
11291     {
11292         MSG msg;
11293         if (PeekMessageA(&msg, 0, 0, 0, 1))
11294         {
11295             TranslateMessage(&msg);
11296             DispatchMessage(&msg);
11297         }
11298     }
11299     DestroyWindow(hwnd);
11300 }
11301
11302 START_TEST(msg)
11303 {
11304     BOOL ret;
11305     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
11306
11307     init_procs();
11308
11309     if (!RegisterWindowClasses()) assert(0);
11310
11311     if (pSetWinEventHook)
11312     {
11313         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
11314                                                       GetModuleHandleA(0),
11315                                                       win_event_proc,
11316                                                       0,
11317                                                       GetCurrentThreadId(),
11318                                                       WINEVENT_INCONTEXT);
11319         assert(hEvent_hook);
11320
11321         if (pIsWinEventHookInstalled)
11322         {
11323             UINT event;
11324             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
11325                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
11326         }
11327     }
11328
11329     cbt_hook_thread_id = GetCurrentThreadId();
11330     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
11331     assert(hCBT_hook);
11332
11333     test_winevents();
11334
11335     /* Fix message sequences before removing 4 lines below */
11336 #if 1
11337     if (pUnhookWinEvent && hEvent_hook)
11338     {
11339         ret = pUnhookWinEvent(hEvent_hook);
11340         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11341         pUnhookWinEvent = 0;
11342     }
11343     hEvent_hook = 0;
11344 #endif
11345
11346     test_ShowWindow();
11347     test_PeekMessage();
11348     test_PeekMessage2();
11349     test_scrollwindowex();
11350     test_messages();
11351     test_setwindowpos();
11352     test_showwindow();
11353     invisible_parent_tests();
11354     test_mdi_messages();
11355     test_button_messages();
11356     test_static_messages();
11357     test_listbox_messages();
11358     test_combobox_messages();
11359     test_wmime_keydown_message();
11360     test_paint_messages();
11361     test_interthread_messages();
11362     test_message_conversion();
11363     test_accelerators();
11364     test_timers();
11365     test_timers_no_wnd();
11366     test_set_hook();
11367     test_DestroyWindow();
11368     test_DispatchMessage();
11369     test_SendMessageTimeout();
11370     test_edit_messages();
11371     test_quit_message();
11372     test_SetActiveWindow();
11373
11374     if (!pTrackMouseEvent)
11375         skip("TrackMouseEvent is not available\n");
11376     else
11377         test_TrackMouseEvent();
11378
11379     test_SetWindowRgn();
11380     test_sys_menu();
11381     test_dialog_messages();
11382     test_nullCallback();
11383     test_dbcs_wm_char();
11384     test_menu_messages();
11385     test_paintingloop();
11386     /* keep it the last test, under Windows it tends to break the tests
11387      * which rely on active/foreground windows being correct.
11388      */
11389     test_SetForegroundWindow();
11390
11391     UnhookWindowsHookEx(hCBT_hook);
11392     if (pUnhookWinEvent)
11393     {
11394         ret = pUnhookWinEvent(hEvent_hook);
11395         ok( ret, "UnhookWinEvent error %d\n", GetLastError());
11396         SetLastError(0xdeadbeef);
11397         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
11398         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
11399            GetLastError() == 0xdeadbeef, /* Win9x */
11400            "unexpected error %d\n", GetLastError());
11401     }
11402     else
11403         skip("UnhookWinEvent is not available\n");
11404 }