secur32: Update ntlm_auth version detection to detect new samba4 version numbers.
[wine] / dlls / user / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */
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
43 #define WND_PARENT_ID           1
44 #define WND_POPUP_ID            2
45 #define WND_CHILD_ID            3
46
47 static BOOL test_DestroyWindow_flag;
48 static HWINEVENTHOOK hEvent_hook;
49
50 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
51
52 /*
53 FIXME: add tests for these
54 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
55  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
56  WS_THICKFRAME: thick border
57  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
58  WS_BORDER (default for overlapped windows): single black border
59  none (default for child (and popup?) windows): no border
60 */
61
62 typedef enum {
63     sent=0x1,
64     posted=0x2,
65     parent=0x4,
66     wparam=0x8,
67     lparam=0x10,
68     defwinproc=0x20,
69     beginpaint=0x40,
70     optional=0x80,
71     hook=0x100,
72     winevent_hook=0x200
73 } msg_flags_t;
74
75 struct message {
76     UINT message;          /* the WM_* code */
77     msg_flags_t flags;     /* message props */
78     WPARAM wParam;         /* expected value of wParam */
79     LPARAM lParam;         /* expected value of lParam */
80 };
81
82 /* Empty message sequence */
83 static const struct message WmEmptySeq[] =
84 {
85     { 0 }
86 };
87 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
88 static const struct message WmCreateOverlappedSeq[] = {
89     { HCBT_CREATEWND, hook },
90     { WM_GETMINMAXINFO, sent },
91     { WM_NCCREATE, sent },
92     { WM_NCCALCSIZE, sent|wparam, 0 },
93     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
94     { WM_CREATE, sent },
95     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
96     { 0 }
97 };
98 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
99  * for a not visible overlapped window.
100  */
101 static const struct message WmSWP_ShowOverlappedSeq[] = {
102     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
103     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
104     { WM_NCPAINT, sent|wparam|optional, 1 },
105     { WM_GETTEXT, sent|defwinproc|optional },
106     { WM_ERASEBKGND, sent|optional },
107     { HCBT_ACTIVATE, hook },
108     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
109     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
110     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
111     { WM_ACTIVATEAPP, sent|wparam, 1 },
112     { WM_NCACTIVATE, sent|wparam, 1 },
113     { WM_GETTEXT, sent|defwinproc|optional },
114     { WM_ACTIVATE, sent|wparam, 1 },
115     { HCBT_SETFOCUS, hook },
116     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
117     { WM_IME_NOTIFY, sent|defwinproc|optional },
118     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
119     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
120     { WM_NCPAINT, sent|wparam|optional, 1 },
121     { WM_GETTEXT, sent|defwinproc|optional },
122     { WM_ERASEBKGND, sent|optional },
123     /* Win9x adds SWP_NOZORDER below */
124     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
125     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
126     { WM_NCPAINT, sent|wparam|optional, 1 },
127     { WM_ERASEBKGND, sent|optional },
128     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
129     { 0 }
130 };
131 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
132  * for a visible overlapped window.
133  */
134 static const struct message WmSWP_HideOverlappedSeq[] = {
135     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
136     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
137     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
138     { 0 }
139 };
140
141 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
142  * for a visible overlapped window.
143  */
144 static const struct message WmSWP_ResizeSeq[] = {
145     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE },
146     { WM_GETMINMAXINFO, sent|defwinproc },
147     { WM_NCCALCSIZE, sent|wparam, TRUE },
148     { WM_NCPAINT, sent|optional },
149     { WM_GETTEXT, sent|defwinproc|optional },
150     { WM_ERASEBKGND, sent|optional },
151     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
152     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
153     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
154     { WM_NCPAINT, sent|optional },
155     { WM_GETTEXT, sent|defwinproc|optional },
156     { WM_ERASEBKGND, sent|optional },
157     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
158     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
159     { 0 }
160 };
161
162 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
163  * for a visible popup window.
164  */
165 static const struct message WmSWP_ResizePopupSeq[] = {
166     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE },
167     { WM_NCCALCSIZE, sent|wparam, TRUE },
168     { WM_NCPAINT, sent|optional },
169     { WM_GETTEXT, sent|defwinproc|optional },
170     { WM_ERASEBKGND, sent|optional },
171     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
172     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
173     { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
174     { WM_NCPAINT, sent|optional },
175     { WM_GETTEXT, sent|defwinproc|optional },
176     { WM_ERASEBKGND, sent|optional },
177     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
178     { 0 }
179 };
180
181 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
182  * for a visible overlapped window.
183  */
184 static const struct message WmSWP_MoveSeq[] = {
185     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE },
186     { WM_NCPAINT, sent|optional },
187     { WM_GETTEXT, sent|defwinproc|optional },
188     { WM_ERASEBKGND, sent|optional },
189     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE },
190     { WM_MOVE, sent|defwinproc|wparam, 0 },
191     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
192     { 0 }
193 };
194
195 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
196                 SWP_NOZORDER|SWP_FRAMECHANGED)
197  * for a visible overlapped window with WS_CLIPCHILDREN style set.
198  */
199 static const struct message WmSWP_FrameChanged_clip[] = {
200     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED },
201     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
202     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
203     { WM_GETTEXT, sent|parent|defwinproc|optional },
204     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
205     { WM_NCPAINT, sent }, /* wparam != 1 */
206     { WM_ERASEBKGND, sent },
207     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
208     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
209     { WM_PAINT, sent },
210     { 0 }
211 };
212 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
213                 SWP_NOZORDER|SWP_FRAMECHANGED)
214  * for a visible overlapped window.
215  */
216 static const struct message WmSWP_FrameChangedDeferErase[] = {
217     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED },
218     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
219     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
220     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
221     { WM_PAINT, sent|parent },
222     { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */
223     { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
224     { WM_PAINT, sent },
225     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
226     { WM_ERASEBKGND, sent|beginpaint },
227     { 0 }
228 };
229
230 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
231                 SWP_NOZORDER|SWP_FRAMECHANGED)
232  * for a visible overlapped window without WS_CLIPCHILDREN style set.
233  */
234 static const struct message WmSWP_FrameChanged_noclip[] = {
235     { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED },
236     { WM_NCCALCSIZE, sent|wparam|parent, 1 },
237     { WM_NCPAINT, sent|parent }, /* wparam != 1 */
238     { WM_GETTEXT, sent|parent|defwinproc|optional },
239     { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
240     { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
241     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
242     { WM_PAINT, sent },
243     { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
244     { WM_ERASEBKGND, sent|beginpaint },
245     { 0 }
246 };
247
248 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
249 static const struct message WmShowOverlappedSeq[] = {
250     { WM_SHOWWINDOW, sent|wparam, 1 },
251     { WM_NCPAINT, sent|wparam|optional, 1 },
252     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
253     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
254     { WM_NCPAINT, sent|wparam|optional, 1 },
255     { WM_GETTEXT, sent|defwinproc|optional },
256     { WM_ERASEBKGND, sent|optional },
257     { HCBT_ACTIVATE, hook },
258     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
259     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
260     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
261     { WM_ACTIVATEAPP, sent|wparam, 1 },
262     { WM_NCACTIVATE, sent|wparam, 1 },
263     { WM_GETTEXT, sent|defwinproc|optional },
264     { WM_ACTIVATE, sent|wparam, 1 },
265     { HCBT_SETFOCUS, hook },
266     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
267     { WM_IME_NOTIFY, sent|defwinproc|optional },
268     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
269     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
270     { WM_NCPAINT, sent|wparam|optional, 1 },
271     { WM_GETTEXT, sent|defwinproc|optional },
272     { WM_ERASEBKGND, sent|optional },
273     /* Win9x adds SWP_NOZORDER below */
274     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
275     { WM_NCCALCSIZE, sent|optional },
276     { WM_NCPAINT, sent|optional },
277     { WM_ERASEBKGND, sent|optional },
278 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
279        * messages. Does that mean that CreateWindow doesn't set initial
280        * window dimensions for overlapped windows?
281        */
282     { WM_SIZE, sent },
283     { WM_MOVE, sent },
284 #endif
285     { 0 }
286 };
287 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
288 static const struct message WmShowMaxOverlappedSeq[] = {
289     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
290     { WM_GETMINMAXINFO, sent },
291     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
292     { WM_GETMINMAXINFO, sent|defwinproc },
293     { WM_NCCALCSIZE, sent|wparam, TRUE },
294     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
295     { HCBT_ACTIVATE, hook },
296     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
297     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
298     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
299     { WM_ACTIVATEAPP, sent|wparam, 1 },
300     { WM_NCACTIVATE, sent|wparam, 1 },
301     { WM_GETTEXT, sent|defwinproc|optional },
302     { WM_ACTIVATE, sent|wparam, 1 },
303     { HCBT_SETFOCUS, hook },
304     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
305     { WM_IME_NOTIFY, sent|defwinproc|optional },
306     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
307     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
308     { WM_NCPAINT, sent|wparam|optional, 1 },
309     { WM_GETTEXT, sent|defwinproc|optional },
310     { WM_ERASEBKGND, sent|optional },
311     /* Win9x adds SWP_NOZORDER below */
312     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
313     { WM_MOVE, sent|defwinproc },
314     { WM_SIZE, sent|defwinproc },
315     { WM_NCCALCSIZE, sent|optional },
316     { WM_NCPAINT, sent|optional },
317     { WM_ERASEBKGND, sent|optional },
318     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
319     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
320     { 0 }
321 };
322 /* ShowWindow(SW_HIDE) for a visible overlapped window */
323 static const struct message WmHideOverlappedSeq[] = {
324     { WM_SHOWWINDOW, sent|wparam, 0 },
325     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
326     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
327     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
328     { WM_SIZE, sent|optional }, /* XP doesn't send it */
329     { WM_MOVE, sent|optional }, /* XP doesn't send it */
330     { WM_NCACTIVATE, sent|wparam, 0 },
331     { WM_ACTIVATE, sent|wparam, 0 },
332     { WM_ACTIVATEAPP, sent|wparam, 0 },
333     { WM_KILLFOCUS, sent|wparam, 0 },
334     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
335     { WM_IME_NOTIFY, sent|optional|defwinproc },
336     { 0 }
337 };
338 /* DestroyWindow for a visible overlapped window */
339 static const struct message WmDestroyOverlappedSeq[] = {
340     { HCBT_DESTROYWND, hook },
341     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
342     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
343     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
344     { WM_NCACTIVATE, sent|wparam, 0 },
345     { WM_ACTIVATE, sent|wparam, 0 },
346     { WM_ACTIVATEAPP, sent|wparam, 0 },
347     { WM_KILLFOCUS, sent|wparam, 0 },
348     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
349     { WM_IME_NOTIFY, sent|optional|defwinproc },
350     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
351     { WM_DESTROY, sent },
352     { WM_NCDESTROY, sent },
353     { 0 }
354 };
355 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
356 static const struct message WmCreateMaxPopupSeq[] = {
357     { HCBT_CREATEWND, hook },
358     { WM_NCCREATE, sent },
359     { WM_NCCALCSIZE, sent|wparam, 0 },
360     { WM_CREATE, sent },
361     { WM_SIZE, sent },
362     { WM_MOVE, sent },
363     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
364     { WM_GETMINMAXINFO, sent },
365     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000*/ },
366     { WM_NCCALCSIZE, sent|wparam, TRUE },
367     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOZORDER|0x8000*/ },
368     { WM_MOVE, sent|defwinproc },
369     { WM_SIZE, sent|defwinproc },
370     { WM_SHOWWINDOW, sent|wparam, 1 },
371     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
372     { HCBT_ACTIVATE, hook },
373     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
374     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
375     { WM_ACTIVATEAPP, sent|wparam, 1 },
376     { WM_NCACTIVATE, sent|wparam, 1 },
377     { WM_ACTIVATE, sent|wparam, 1 },
378     { HCBT_SETFOCUS, hook },
379     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
380     { WM_SYNCPAINT, sent|wparam|optional, 4 },
381     { WM_NCPAINT, sent|wparam|optional, 1 },
382     { WM_ERASEBKGND, sent|optional },
383     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOSIZE },
384     { 0 }
385 };
386 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
387 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
388     { HCBT_CREATEWND, hook },
389     { WM_NCCREATE, sent },
390     { WM_NCCALCSIZE, sent|wparam, 0 },
391     { WM_CREATE, sent },
392     { WM_SIZE, sent },
393     { WM_MOVE, sent },
394     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
395     { WM_GETMINMAXINFO, sent },
396     { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|0x8000*/ },
397     { WM_NCCALCSIZE, sent|wparam, TRUE },
398     { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOZORDER|0x8000*/ },
399     { WM_MOVE, sent|defwinproc },
400     { WM_SIZE, sent|defwinproc },
401     { 0 }
402 };
403 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
404 static const struct message WmShowMaxPopupResizedSeq[] = {
405     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
406     { WM_GETMINMAXINFO, sent },
407     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
408     { WM_NCCALCSIZE, sent|wparam, TRUE },
409     { HCBT_ACTIVATE, hook },
410     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
411     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
412     { WM_ACTIVATEAPP, sent|wparam, 1 },
413     { WM_NCACTIVATE, sent|wparam, 1 },
414     { WM_ACTIVATE, sent|wparam, 1 },
415     { HCBT_SETFOCUS, hook },
416     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
417     { WM_NCPAINT, sent|wparam|optional, 1 },
418     { WM_ERASEBKGND, sent|optional },
419     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOZORDER },
420     /* WinNT4.0 sends WM_MOVE */
421     { WM_MOVE, sent|defwinproc|optional },
422     { WM_SIZE, sent|defwinproc },
423     { 0 }
424 };
425 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
426 static const struct message WmShowMaxPopupSeq[] = {
427     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
428     { WM_GETMINMAXINFO, sent },
429     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
430     { WM_NCCALCSIZE, sent|wparam, TRUE },
431     { HCBT_ACTIVATE, hook },
432     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
433     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
434     { WM_ACTIVATEAPP, sent|wparam, 1 },
435     { WM_NCACTIVATE, sent|wparam, 1 },
436     { WM_ACTIVATE, sent|wparam, 1 },
437     { HCBT_SETFOCUS, hook },
438     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
439     { WM_SYNCPAINT, sent|wparam|optional, 4 },
440     { WM_NCPAINT, sent|wparam|optional, 1 },
441     { WM_ERASEBKGND, sent|optional },
442     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
443     { 0 }
444 };
445 /* CreateWindow(WS_VISIBLE) for popup window */
446 static const struct message WmCreatePopupSeq[] = {
447     { HCBT_CREATEWND, hook },
448     { WM_NCCREATE, sent },
449     { WM_NCCALCSIZE, sent|wparam, 0 },
450     { WM_CREATE, sent },
451     { WM_SIZE, sent },
452     { WM_MOVE, sent },
453     { WM_SHOWWINDOW, sent|wparam, 1 },
454     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
455     { HCBT_ACTIVATE, hook },
456     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
457     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
458     { WM_NCPAINT, sent|wparam|optional, 1 },
459     { WM_ERASEBKGND, sent|optional },
460     { WM_ACTIVATEAPP, sent|wparam, 1 },
461     { WM_NCACTIVATE, sent|wparam, 1 },
462     { WM_ACTIVATE, sent|wparam, 1 },
463     { HCBT_SETFOCUS, hook },
464     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
465     { WM_SYNCPAINT, sent|wparam|optional, 4 },
466     { WM_NCPAINT, sent|wparam|optional, 1 },
467     { WM_ERASEBKGND, sent|optional },
468     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOSIZE },
469     { 0 }
470 };
471 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
472 static const struct message WmShowVisMaxPopupSeq[] = {
473     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
474     { WM_GETMINMAXINFO, sent },
475     { WM_GETTEXT, sent|optional },
476     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
477     { WM_NCCALCSIZE, sent|wparam, TRUE },
478     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
479     { WM_NCPAINT, sent|wparam|optional, 1 },
480     { WM_ERASEBKGND, sent|optional },
481     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOZORDER|0x8000 },
482     { WM_MOVE, sent|defwinproc },
483     { WM_SIZE, sent|defwinproc },
484     { 0 }
485 };
486 /* CreateWindow (for a child popup window, not initially visible) */
487 static const struct message WmCreateChildPopupSeq[] = {
488     { HCBT_CREATEWND, hook },
489     { WM_NCCREATE, sent }, 
490     { WM_NCCALCSIZE, sent|wparam, 0 },
491     { WM_CREATE, sent },
492     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
493     { WM_SIZE, sent },
494     { WM_MOVE, sent },
495     { 0 }
496 };
497 /* CreateWindow (for a popup window, not initially visible,
498  * which sets WS_VISIBLE in WM_CREATE handler)
499  */
500 static const struct message WmCreateInvisiblePopupSeq[] = {
501     { HCBT_CREATEWND, hook },
502     { WM_NCCREATE, sent }, 
503     { WM_NCCALCSIZE, sent|wparam, 0 },
504     { WM_CREATE, sent },
505     { WM_STYLECHANGING, sent },
506     { WM_STYLECHANGED, sent },
507     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
508     { WM_SIZE, sent },
509     { WM_MOVE, sent },
510     { 0 }
511 };
512 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
513  * for a popup window with WS_VISIBLE style set
514  */
515 static const struct message WmShowVisiblePopupSeq_2[] = {
516     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
517     { 0 }
518 };
519 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
520  * for a popup window with WS_VISIBLE style set
521  */
522 static const struct message WmShowVisiblePopupSeq_3[] = {
523     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
524     { HCBT_ACTIVATE, hook },
525     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
526     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
527     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
528     { WM_NCACTIVATE, sent|wparam, 1 },
529     { WM_ACTIVATE, sent|wparam, 1 },
530     { HCBT_SETFOCUS, hook },
531     { WM_KILLFOCUS, sent|parent },
532     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
533     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
534     { WM_IME_NOTIFY, sent|defwinproc|optional },
535     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
536     { WM_SETFOCUS, sent|defwinproc },
537     { 0 }
538 };
539 /* CreateWindow (for child window, not initially visible) */
540 static const struct message WmCreateChildSeq[] = {
541     { HCBT_CREATEWND, hook },
542     { WM_NCCREATE, sent }, 
543     /* child is inserted into parent's child list after WM_NCCREATE returns */
544     { WM_NCCALCSIZE, sent|wparam, 0 },
545     { WM_CREATE, sent },
546     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
547     { WM_SIZE, sent },
548     { WM_MOVE, sent },
549     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
550     { 0 }
551 };
552 /* CreateWindow (for maximized child window, not initially visible) */
553 static const struct message WmCreateMaximizedChildSeq[] = {
554     { HCBT_CREATEWND, hook },
555     { WM_NCCREATE, sent }, 
556     { WM_NCCALCSIZE, sent|wparam, 0 },
557     { WM_CREATE, sent },
558     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
559     { WM_SIZE, sent },
560     { WM_MOVE, sent },
561     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
562     { WM_GETMINMAXINFO, sent },
563     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
564     { WM_NCCALCSIZE, sent|wparam, 1 },
565     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
566     { WM_SIZE, sent|defwinproc },
567     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
568     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
569     { 0 }
570 };
571 /* CreateWindow (for a child window, initially visible) */
572 static const struct message WmCreateVisibleChildSeq[] = {
573     { HCBT_CREATEWND, hook },
574     { WM_NCCREATE, sent }, 
575     /* child is inserted into parent's child list after WM_NCCREATE returns */
576     { WM_NCCALCSIZE, sent|wparam, 0 },
577     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
578     { WM_CREATE, sent },
579     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
580     { WM_SIZE, sent },
581     { WM_MOVE, sent },
582     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
583     { WM_SHOWWINDOW, sent|wparam, 1 },
584     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
585     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
586     { WM_ERASEBKGND, sent|parent|optional },
587     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
588     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
589     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
590     { 0 }
591 };
592 /* ShowWindow(SW_SHOW) for a not visible child window */
593 static const struct message WmShowChildSeq[] = {
594     { WM_SHOWWINDOW, sent|wparam, 1 },
595     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
596     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
597     { WM_ERASEBKGND, sent|parent|optional },
598     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
599     { 0 }
600 };
601 /* ShowWindow(SW_HIDE) for a visible child window */
602 static const struct message WmHideChildSeq[] = {
603     { WM_SHOWWINDOW, sent|wparam, 0 },
604     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
605     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
606     { WM_ERASEBKGND, sent|parent|optional },
607     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
608     { 0 }
609 };
610 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
611  * for a not visible child window
612  */
613 static const struct message WmShowChildSeq_2[] = {
614     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
615     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
616     { WM_CHILDACTIVATE, sent },
617     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
618     { 0 }
619 };
620 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
621  * for a not visible child window
622  */
623 static const struct message WmShowChildSeq_3[] = {
624     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
625     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
626     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
627     { 0 }
628 };
629 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
630  * for a visible child window with a caption
631  */
632 static const struct message WmShowChildSeq_4[] = {
633     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
634     { WM_CHILDACTIVATE, sent },
635     { 0 }
636 };
637 /* ShowWindow(SW_SHOW) for child with invisible parent */
638 static const struct message WmShowChildInvisibleParentSeq[] = {
639     { WM_SHOWWINDOW, sent|wparam, 1 },
640     { 0 }
641 };
642 /* ShowWindow(SW_HIDE) for child with invisible parent */
643 static const struct message WmHideChildInvisibleParentSeq[] = {
644     { WM_SHOWWINDOW, sent|wparam, 0 },
645     { 0 }
646 };
647 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
648 static const struct message WmShowChildInvisibleParentSeq_2[] = {
649     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
650     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
651     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
652     { 0 }
653 };
654 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
655 static const struct message WmHideChildInvisibleParentSeq_2[] = {
656     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
657     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
658     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
659     { 0 }
660 };
661 /* DestroyWindow for a visible child window */
662 static const struct message WmDestroyChildSeq[] = {
663     { HCBT_DESTROYWND, hook },
664     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
665     { WM_SHOWWINDOW, sent|wparam, 0 },
666     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
667     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
668     { WM_ERASEBKGND, sent|parent|optional },
669     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
670     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
671     { WM_KILLFOCUS, sent },
672     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
673     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
674     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
675     { WM_SETFOCUS, sent|parent },
676     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
677     { WM_DESTROY, sent },
678     { WM_DESTROY, sent|optional }, /* some other (IME?) window */
679     { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
680     { WM_NCDESTROY, sent },
681     { 0 }
682 };
683 /* DestroyWindow for a visible child window with invisible parent */
684 static const struct message WmDestroyInvisibleChildSeq[] = {
685     { HCBT_DESTROYWND, hook },
686     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
687     { WM_SHOWWINDOW, sent|wparam, 0 },
688     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
689     { WM_DESTROY, sent },
690     { WM_NCDESTROY, sent },
691     { 0 }
692 };
693 /* Moving the mouse in nonclient area */
694 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
695     { WM_NCHITTEST, sent },
696     { WM_SETCURSOR, sent },
697     { WM_NCMOUSEMOVE, posted },
698     { 0 }
699 };
700 /* Moving the mouse in client area */
701 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
702     { WM_NCHITTEST, sent },
703     { WM_SETCURSOR, sent },
704     { WM_MOUSEMOVE, posted },
705     { 0 }
706 };
707 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
708 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
709     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
710     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
711     { WM_GETMINMAXINFO, sent|defwinproc },
712     { WM_ENTERSIZEMOVE, sent|defwinproc },
713     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
714     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
715     { WM_MOVE, sent|defwinproc },
716     { WM_EXITSIZEMOVE, sent|defwinproc },
717     { 0 }
718 };
719 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
720 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
721     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
722     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
723     { WM_GETMINMAXINFO, sent|defwinproc },
724     { WM_ENTERSIZEMOVE, sent|defwinproc },
725     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
726     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
727     { WM_GETMINMAXINFO, sent|defwinproc },
728     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
729     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
730     { WM_GETTEXT, sent|defwinproc },
731     { WM_ERASEBKGND, sent|defwinproc },
732     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
733     { WM_MOVE, sent|defwinproc },
734     { WM_SIZE, sent|defwinproc },
735     { WM_EXITSIZEMOVE, sent|defwinproc },
736     { 0 }
737 };
738 /* Resizing child window with MoveWindow (32) */
739 static const struct message WmResizingChildWithMoveWindowSeq[] = {
740     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
741     { WM_NCCALCSIZE, sent|wparam, 1 },
742     { WM_ERASEBKGND, sent|optional },
743     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
744     { WM_MOVE, sent|defwinproc },
745     { WM_SIZE, sent|defwinproc },
746     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
747     { 0 }
748 };
749 /* Clicking on inactive button */
750 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
751     { WM_NCHITTEST, sent },
752     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
753     { WM_MOUSEACTIVATE, sent },
754     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
755     { WM_SETCURSOR, sent },
756     { WM_SETCURSOR, sent|parent|defwinproc },
757     { WM_LBUTTONDOWN, posted },
758     { WM_KILLFOCUS, posted|parent },
759     { WM_SETFOCUS, posted },
760     { WM_CTLCOLORBTN, posted|parent },
761     { BM_SETSTATE, posted },
762     { WM_CTLCOLORBTN, posted|parent },
763     { WM_LBUTTONUP, posted },
764     { BM_SETSTATE, posted },
765     { WM_CTLCOLORBTN, posted|parent },
766     { WM_COMMAND, posted|parent },
767     { 0 }
768 };
769 /* Reparenting a button (16/32) */
770 /* The last child (button) reparented gets topmost for its new parent. */
771 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
772     { WM_SHOWWINDOW, sent|wparam, 0 },
773     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
774     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
775     { WM_ERASEBKGND, sent|parent },
776     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
777     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
778     { WM_CHILDACTIVATE, sent },
779     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
780     { WM_MOVE, sent|defwinproc },
781     { WM_SHOWWINDOW, sent|wparam, 1 },
782     { 0 }
783 };
784 /* Creation of a custom dialog (32) */
785 static const struct message WmCreateCustomDialogSeq[] = {
786     { HCBT_CREATEWND, hook },
787     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
788     { WM_GETMINMAXINFO, sent },
789     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
790     { WM_NCCREATE, sent },
791     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
792     { WM_NCCALCSIZE, sent|wparam, 0 },
793     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
794     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
795     { WM_CREATE, sent },
796     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
797     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
798     { WM_SHOWWINDOW, sent|wparam, 1 },
799     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
800     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
801     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
802     { HCBT_ACTIVATE, hook },
803     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
804
805     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
806
807     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
808     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
809
810     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
811
812     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
813     { WM_NCACTIVATE, sent|wparam, 1 },
814     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
815     { WM_GETTEXT, sent|optional|defwinproc },
816     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
817     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
818     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
819     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
820     { WM_GETTEXT, sent|optional|defwinproc },
821     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
822     { WM_ACTIVATE, sent|wparam, 1 },
823     { WM_KILLFOCUS, sent|parent },
824     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
825     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
826     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
827     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
828     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
829     { WM_IME_NOTIFY, sent|optional|defwinproc },
830     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
831     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
832     { WM_SETFOCUS, sent },
833     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
834     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
835     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
836     { WM_NCPAINT, sent|wparam, 1 },
837     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
838     { WM_GETTEXT, sent|optional|defwinproc },
839     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
840     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
841     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
842     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
843     { WM_GETTEXT, sent|optional|defwinproc },
844     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
845     { WM_ERASEBKGND, sent },
846     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
847     { WM_CTLCOLORDLG, sent|defwinproc },
848     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
849     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
850     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
851     { WM_GETTEXT, sent|optional },
852     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
853     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
854     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
855     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
856     { WM_GETTEXT, sent|optional },
857     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
858     { WM_NCCALCSIZE, sent|optional },
859     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
860     { WM_NCPAINT, sent|optional },
861     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
862     { WM_GETTEXT, sent|optional|defwinproc },
863     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
864     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
865     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
866     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
867     { WM_GETTEXT, sent|optional|defwinproc },
868     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
869     { WM_ERASEBKGND, sent|optional },
870     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
871     { WM_CTLCOLORDLG, sent|optional|defwinproc },
872     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
873     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
874     { WM_SIZE, sent },
875     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
876     { WM_MOVE, sent },
877     { 0 }
878 };
879 /* Calling EndDialog for a custom dialog (32) */
880 static const struct message WmEndCustomDialogSeq[] = {
881     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
882     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
883     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
884     { WM_GETTEXT, sent|optional },
885     { HCBT_ACTIVATE, hook },
886     { WM_NCACTIVATE, sent|wparam, 0 },
887     { WM_GETTEXT, sent|optional|defwinproc },
888     { WM_GETTEXT, sent|optional|defwinproc },
889     { WM_ACTIVATE, sent|wparam, 0 },
890     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
891     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
892     { HCBT_SETFOCUS, hook },
893     { WM_KILLFOCUS, sent },
894     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
895     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
896     { WM_IME_NOTIFY, sent|optional },
897     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
898     { WM_SETFOCUS, sent|parent|defwinproc },
899     { 0 }
900 };
901 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
902 static const struct message WmShowCustomDialogSeq[] = {
903     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
904     { WM_SHOWWINDOW, sent|wparam, 1 },
905     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
906     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
907     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
908     { HCBT_ACTIVATE, hook },
909     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
910
911     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
912     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
913
914     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
915     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
916     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
917     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
918     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
919     { WM_NCACTIVATE, sent|wparam, 1 },
920     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
921     { WM_ACTIVATE, sent|wparam, 1 },
922
923     { WM_KILLFOCUS, sent|parent },
924     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
925     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
926     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
927     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
928     { WM_IME_NOTIFY, sent|optional|defwinproc },
929     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
930     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
931     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
932     { WM_SETFOCUS, sent },
933     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
934     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
935     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
936     { WM_NCPAINT, sent|wparam, 1 },
937     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
938     { WM_ERASEBKGND, sent },
939     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
940     { WM_CTLCOLORDLG, sent|defwinproc },
941
942     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
943     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
944     { 0 }
945 };
946 /* Creation and destruction of a modal dialog (32) */
947 static const struct message WmModalDialogSeq[] = {
948     { WM_CANCELMODE, sent|parent },
949     { HCBT_SETFOCUS, hook },
950     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
951     { WM_KILLFOCUS, sent|parent },
952     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
953     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
954     { WM_ENABLE, sent|parent|wparam, 0 },
955     { HCBT_CREATEWND, hook },
956     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
957     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
958     { WM_SETFONT, sent },
959     { WM_INITDIALOG, sent },
960     { WM_CHANGEUISTATE, sent|optional },
961     { WM_SHOWWINDOW, sent },
962     { HCBT_ACTIVATE, hook },
963     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
964     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
965     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
966     { WM_NCACTIVATE, sent|wparam, 1 },
967     { WM_GETTEXT, sent|optional },
968     { WM_ACTIVATE, sent|wparam, 1 },
969     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE },
970     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
971     { WM_NCPAINT, sent },
972     { WM_GETTEXT, sent|optional },
973     { WM_ERASEBKGND, sent },
974     { WM_CTLCOLORDLG, sent },
975     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
976     { WM_GETTEXT, sent|optional },
977     { WM_NCCALCSIZE, sent|optional },
978     { WM_NCPAINT, sent|optional },
979     { WM_GETTEXT, sent|optional },
980     { WM_ERASEBKGND, sent|optional },
981     { WM_CTLCOLORDLG, sent|optional },
982     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
983     { WM_PAINT, sent|optional },
984     { WM_CTLCOLORBTN, sent },
985     { WM_ENTERIDLE, sent|parent|optional },
986     { WM_ENTERIDLE, sent|parent|optional },
987     { WM_ENTERIDLE, sent|parent|optional },
988     { WM_ENTERIDLE, sent|parent|optional },
989     { WM_ENTERIDLE, sent|parent|optional },
990     { WM_ENTERIDLE, sent|parent|optional },
991     { WM_ENTERIDLE, sent|parent|optional },
992     { WM_ENTERIDLE, sent|parent|optional },
993     { WM_ENTERIDLE, sent|parent|optional },
994     { WM_ENTERIDLE, sent|parent|optional },
995     { WM_ENTERIDLE, sent|parent|optional },
996     { WM_ENTERIDLE, sent|parent|optional },
997     { WM_ENTERIDLE, sent|parent|optional },
998     { WM_ENTERIDLE, sent|parent|optional },
999     { WM_ENTERIDLE, sent|parent|optional },
1000     { WM_ENTERIDLE, sent|parent|optional },
1001     { WM_ENTERIDLE, sent|parent|optional },
1002     { WM_ENTERIDLE, sent|parent|optional },
1003     { WM_ENTERIDLE, sent|parent|optional },
1004     { WM_ENTERIDLE, sent|parent|optional },
1005     { WM_TIMER, sent },
1006     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1007     { WM_ENABLE, sent|parent|wparam, 1 },
1008     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE },
1009     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1010     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1011     { WM_GETTEXT, sent|optional },
1012     { HCBT_ACTIVATE, hook },
1013     { WM_NCACTIVATE, sent|wparam, 0 },
1014     { WM_GETTEXT, sent|optional },
1015     { WM_ACTIVATE, sent|wparam, 0 },
1016     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1017     { WM_WINDOWPOSCHANGING, sent|optional },
1018     { HCBT_SETFOCUS, hook },
1019     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1020     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1021     { WM_SETFOCUS, sent|parent|defwinproc },
1022     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1023     { HCBT_DESTROYWND, hook },
1024     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1025     { WM_DESTROY, sent },
1026     { WM_NCDESTROY, sent },
1027     { 0 }
1028 };
1029 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
1030 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
1031     /* (inside dialog proc, handling WM_INITDIALOG) */
1032     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1033     { WM_NCCALCSIZE, sent },
1034     { WM_NCACTIVATE, sent|parent|wparam, 0 },
1035     { WM_GETTEXT, sent|defwinproc },
1036     { WM_ACTIVATE, sent|parent|wparam, 0 },
1037     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1038     { WM_WINDOWPOSCHANGING, sent|parent },
1039     { WM_NCACTIVATE, sent|wparam, 1 },
1040     { WM_ACTIVATE, sent|wparam, 1 },
1041     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1042     { WM_SIZE, sent|defwinproc },
1043     /* (setting focus) */
1044     { WM_SHOWWINDOW, sent|wparam, 1 },
1045     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
1046     { WM_NCPAINT, sent },
1047     { WM_GETTEXT, sent|defwinproc },
1048     { WM_ERASEBKGND, sent },
1049     { WM_CTLCOLORDLG, sent|defwinproc },
1050     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
1051     { WM_PAINT, sent },
1052     /* (bunch of WM_CTLCOLOR* for each control) */
1053     { WM_PAINT, sent|parent },
1054     { WM_ENTERIDLE, sent|parent|wparam, 0 },
1055     { WM_SETCURSOR, sent|parent },
1056     { 0 }
1057 };
1058 /* SetMenu for NonVisible windows with size change*/
1059 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1060     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1061     { WM_NCCALCSIZE, sent|wparam, 1 },
1062     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1063     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW },
1064     { WM_MOVE, sent|defwinproc },
1065     { WM_SIZE, sent|defwinproc },
1066     { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1067     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1068     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1069     { WM_GETTEXT, sent|optional },
1070     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1071     { 0 }
1072 };
1073 /* SetMenu for NonVisible windows with no size change */
1074 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1075     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1076     { WM_NCCALCSIZE, sent|wparam, 1 },
1077     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1078     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1079     { 0 }
1080 };
1081 /* SetMenu for Visible windows with size change */
1082 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1083     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1084     { WM_NCCALCSIZE, sent|wparam, 1 },
1085     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1086     { WM_NCPAINT, sent }, /* wparam != 1 */
1087     { WM_GETTEXT, sent|defwinproc|optional },
1088     { WM_ERASEBKGND, sent|optional },
1089     { WM_ACTIVATE, sent|optional },
1090     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1091     { WM_MOVE, sent|defwinproc },
1092     { WM_SIZE, sent|defwinproc },
1093     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1094     { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1095     { WM_ERASEBKGND, sent|optional },
1096     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1097     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1098     { 0 }
1099 };
1100 /* SetMenu for Visible windows with no size change */
1101 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1102     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1103     { WM_NCCALCSIZE, sent|wparam, 1 },
1104     { WM_NCPAINT, sent }, /* wparam != 1 */
1105     { WM_GETTEXT, sent|defwinproc|optional },
1106     { WM_ERASEBKGND, sent|optional },
1107     { WM_ACTIVATE, sent|optional },
1108     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1109     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1110     { 0 }
1111 };
1112 /* DrawMenuBar for a visible window */
1113 static const struct message WmDrawMenuBarSeq[] =
1114 {
1115     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1116     { WM_NCCALCSIZE, sent|wparam, 1 },
1117     { WM_NCPAINT, sent }, /* wparam != 1 */
1118     { WM_GETTEXT, sent|defwinproc|optional },
1119     { WM_ERASEBKGND, sent|optional },
1120     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1121     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1122     { 0 }
1123 };
1124
1125 static const struct message WmSetRedrawFalseSeq[] =
1126 {
1127     { WM_SETREDRAW, sent|wparam, 0 },
1128     { 0 }
1129 };
1130
1131 static const struct message WmSetRedrawTrueSeq[] =
1132 {
1133     { WM_SETREDRAW, sent|wparam, 1 },
1134     { 0 }
1135 };
1136
1137 static const struct message WmEnableWindowSeq_1[] =
1138 {
1139     { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1140     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1141     { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1142     { 0 }
1143 };
1144
1145 static const struct message WmEnableWindowSeq_2[] =
1146 {
1147     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1148     { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1149     { 0 }
1150 };
1151
1152 static const struct message WmGetScrollRangeSeq[] =
1153 {
1154     { SBM_GETRANGE, sent },
1155     { 0 }
1156 };
1157 static const struct message WmGetScrollInfoSeq[] =
1158 {
1159     { SBM_GETSCROLLINFO, sent },
1160     { 0 }
1161 };
1162 static const struct message WmSetScrollRangeSeq[] =
1163 {
1164     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1165        sends SBM_SETSCROLLINFO.
1166      */
1167     { SBM_SETSCROLLINFO, sent },
1168     { 0 }
1169 };
1170 /* SetScrollRange for a window without a non-client area */
1171 static const struct message WmSetScrollRangeHSeq_empty[] =
1172 {
1173     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1174     { 0 }
1175 };
1176 static const struct message WmSetScrollRangeVSeq_empty[] =
1177 {
1178     { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1179     { 0 }
1180 };
1181 static const struct message WmSetScrollRangeHVSeq[] =
1182 {
1183     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
1184     { WM_NCCALCSIZE, sent|wparam, 1 },
1185     { WM_GETTEXT, sent|defwinproc|optional },
1186     { WM_ERASEBKGND, sent|optional },
1187     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1188     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1189     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1190     { 0 }
1191 };
1192 /* SetScrollRange for a window with a non-client area */
1193 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1194 {
1195     { WM_WINDOWPOSCHANGING, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER*/ },
1196     { WM_NCCALCSIZE, sent|wparam, 1 },
1197     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1198     { WM_NCPAINT, sent|optional },
1199     { WM_GETTEXT, sent|defwinproc|optional },
1200     { WM_GETTEXT, sent|defwinproc|optional },
1201     { WM_ERASEBKGND, sent|optional },
1202     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1203     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|0x1000*/ },
1204     { WM_SIZE, sent|defwinproc },
1205     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1206     { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1207     { WM_GETTEXT, sent|optional },
1208     { WM_GETTEXT, sent|optional },
1209     { WM_GETTEXT, sent|optional },
1210     { WM_GETTEXT, sent|optional },
1211     { 0 }
1212 };
1213 /* test if we receive the right sequence of messages */
1214 /* after calling ShowWindow( SW_SHOWNA) */
1215 static const struct message WmSHOWNAChildInvisParInvis[] = {
1216     { WM_SHOWWINDOW, sent|wparam, 1 },
1217     { 0 }
1218 };
1219 static const struct message WmSHOWNAChildVisParInvis[] = {
1220     { WM_SHOWWINDOW, sent|wparam, 1 },
1221     { 0 }
1222 };
1223 static const struct message WmSHOWNAChildVisParVis[] = {
1224     { WM_SHOWWINDOW, sent|wparam, 1 },
1225     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
1226     { 0 }
1227 };
1228 static const struct message WmSHOWNAChildInvisParVis[] = {
1229     { WM_SHOWWINDOW, sent|wparam, 1 },
1230     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER},
1231     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1232     { WM_ERASEBKGND, sent|optional },
1233     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1234     { 0 }
1235 };
1236 static const struct message WmSHOWNATopVisible[] = {
1237     { WM_SHOWWINDOW, sent|wparam, 1 },
1238     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1239     { 0 }
1240 };
1241 static const struct message WmSHOWNATopInvisible[] = {
1242     { WM_SHOWWINDOW, sent|wparam, 1 },
1243     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1244     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1245     { WM_NCPAINT, sent|wparam, 1 },
1246     { WM_GETTEXT, sent|defwinproc|optional },
1247     { WM_ERASEBKGND, sent|optional },
1248     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1249     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1250     { WM_NCPAINT, sent|wparam|optional, 1 },
1251     { WM_ERASEBKGND, sent|optional },
1252     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1253     { WM_SIZE, sent },
1254     { WM_MOVE, sent },
1255     { 0 }
1256 };
1257
1258 static int after_end_dialog;
1259 static int sequence_cnt, sequence_size;
1260 static struct message* sequence;
1261 static int log_all_parent_messages;
1262
1263 static void add_message(const struct message *msg)
1264 {
1265     if (!sequence) 
1266     {
1267         sequence_size = 10;
1268         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
1269     }
1270     if (sequence_cnt == sequence_size) 
1271     {
1272         sequence_size *= 2;
1273         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
1274     }
1275     assert(sequence);
1276
1277     sequence[sequence_cnt].message = msg->message;
1278     sequence[sequence_cnt].flags = msg->flags;
1279     sequence[sequence_cnt].wParam = msg->wParam;
1280     sequence[sequence_cnt].lParam = msg->lParam;
1281
1282     sequence_cnt++;
1283 }
1284
1285 /* try to make sure pending X events have been processed before continuing */
1286 static void flush_events(void)
1287 {
1288     MSG msg;
1289     int diff = 100;
1290     DWORD time = GetTickCount() + diff;
1291
1292     while (diff > 0)
1293     {
1294         MsgWaitForMultipleObjects( 0, NULL, FALSE, diff, QS_ALLINPUT );
1295         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
1296         diff = time - GetTickCount();
1297     }
1298 }
1299
1300 static void flush_sequence(void)
1301 {
1302     HeapFree(GetProcessHeap(), 0, sequence);
1303     sequence = 0;
1304     sequence_cnt = sequence_size = 0;
1305 }
1306
1307 #define ok_sequence( exp, contx, todo) \
1308         ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
1309
1310
1311 static void ok_sequence_(const struct message *expected, const char *context, int todo,
1312         const char *file, int line)
1313 {
1314     static const struct message end_of_sequence = { 0, 0, 0, 0 };
1315     const struct message *actual;
1316     int failcount = 0;
1317     
1318     add_message(&end_of_sequence);
1319
1320     actual = sequence;
1321
1322     while (expected->message && actual->message)
1323     {
1324         trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
1325
1326         if (expected->message == actual->message)
1327         {
1328             if (expected->flags & wparam)
1329             {
1330                 if (expected->wParam != actual->wParam && todo)
1331                 {
1332                     todo_wine {
1333                         failcount ++;
1334                         ok_( file, line) (FALSE,
1335                             "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
1336                             context, expected->message, expected->wParam, actual->wParam);
1337                     }
1338                 }
1339                 else
1340                 ok_( file, line) (expected->wParam == actual->wParam,
1341                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
1342                      context, expected->message, expected->wParam, actual->wParam);
1343             }
1344             if (expected->flags & lparam)
1345                  ok_( file, line) (expected->lParam == actual->lParam,
1346                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
1347                      context, expected->message, expected->lParam, actual->lParam);
1348             ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
1349                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
1350                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
1351             ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
1352                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
1353                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
1354             ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
1355                 "%s: the msg 0x%04x should have been %s\n",
1356                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
1357             ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
1358                 "%s: the msg 0x%04x was expected in %s\n",
1359                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
1360             ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
1361                 "%s: the msg 0x%04x should have been sent by a hook\n",
1362                 context, expected->message);
1363             ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
1364                 "%s: the msg 0x%04x should have been sent by a winevent hook\n",
1365                 context, expected->message);
1366             expected++;
1367             actual++;
1368         }
1369         /* silently drop winevent messages if there is no support for them */
1370         else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
1371             expected++;
1372         else if (todo)
1373         {
1374             failcount++;
1375             todo_wine {
1376                 ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1377                     context, expected->message, actual->message);
1378             }
1379             flush_sequence();
1380             return;
1381         }
1382         else
1383         {
1384             ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
1385                 context, expected->message, actual->message);
1386             expected++;
1387             actual++;
1388         }
1389     }
1390
1391     /* skip all optional trailing messages */
1392     while (expected->message && ((expected->flags & optional) ||
1393             ((expected->flags & winevent_hook) && !hEvent_hook)))
1394         expected++;
1395
1396     if (todo)
1397     {
1398         todo_wine {
1399             if (expected->message || actual->message) {
1400                 failcount++;
1401                 ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1402                     context, expected->message, actual->message);
1403             }
1404         }
1405     }
1406     else
1407     {
1408         if (expected->message || actual->message)
1409             ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
1410                 context, expected->message, actual->message);
1411     }
1412     if( todo && !failcount) /* succeeded yet marked todo */
1413         todo_wine {
1414             ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
1415         }
1416
1417     flush_sequence();
1418 }
1419
1420 /******************************** MDI test **********************************/
1421
1422 /* CreateWindow for MDI frame window, initially visible */
1423 static const struct message WmCreateMDIframeSeq[] = {
1424     { HCBT_CREATEWND, hook },
1425     { WM_GETMINMAXINFO, sent },
1426     { WM_NCCREATE, sent },
1427     { WM_NCCALCSIZE, sent|wparam, 0 },
1428     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1429     { WM_CREATE, sent },
1430     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1431     { WM_SHOWWINDOW, sent|wparam, 1 },
1432     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1433     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1434     { HCBT_ACTIVATE, hook },
1435     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1436     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1437     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1438     { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
1439     { WM_ACTIVATEAPP, sent|wparam, 1 },
1440     { WM_NCACTIVATE, sent|wparam, 1 },
1441     { WM_GETTEXT, sent|defwinproc|optional },
1442     { WM_ACTIVATE, sent|wparam, 1 },
1443     { HCBT_SETFOCUS, hook },
1444     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1445     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1446     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1447     /* Win9x adds SWP_NOZORDER below */
1448     { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
1449     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
1450     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1451     { WM_SIZE, sent },
1452     { WM_MOVE, sent },
1453     { 0 }
1454 };
1455 /* DestroyWindow for MDI frame window, initially visible */
1456 static const struct message WmDestroyMDIframeSeq[] = {
1457     { HCBT_DESTROYWND, hook },
1458     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1459     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1460     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1461     { WM_NCACTIVATE, sent|wparam, 0 },
1462     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
1463     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
1464     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
1465     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1466     { WM_DESTROY, sent },
1467     { WM_NCDESTROY, sent },
1468     { 0 }
1469 };
1470 /* CreateWindow for MDI client window, initially visible */
1471 static const struct message WmCreateMDIclientSeq[] = {
1472     { HCBT_CREATEWND, hook },
1473     { WM_NCCREATE, sent },
1474     { WM_NCCALCSIZE, sent|wparam, 0 },
1475     { WM_CREATE, sent },
1476     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1477     { WM_SIZE, sent },
1478     { WM_MOVE, sent },
1479     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
1480     { WM_SHOWWINDOW, sent|wparam, 1 },
1481     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
1482     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1483     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1484     { 0 }
1485 };
1486 /* DestroyWindow for MDI client window, initially visible */
1487 static const struct message WmDestroyMDIclientSeq[] = {
1488     { HCBT_DESTROYWND, hook },
1489     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
1490     { WM_SHOWWINDOW, sent|wparam, 0 },
1491     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1492     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1493     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1494     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1495     { WM_DESTROY, sent },
1496     { WM_NCDESTROY, sent },
1497     { 0 }
1498 };
1499 /* CreateWindow for MDI child window, initially visible */
1500 static const struct message WmCreateMDIchildVisibleSeq[] = {
1501     { HCBT_CREATEWND, hook },
1502     { WM_NCCREATE, sent }, 
1503     { WM_NCCALCSIZE, sent|wparam, 0 },
1504     { WM_CREATE, sent },
1505     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1506     { WM_SIZE, sent },
1507     { WM_MOVE, sent },
1508     /* Win2k sends wparam set to
1509      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1510      * while Win9x doesn't bother to set child window id according to
1511      * CLIENTCREATESTRUCT.idFirstChild
1512      */
1513     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1514     { WM_SHOWWINDOW, sent|wparam, 1 },
1515     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1516     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1517     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1518     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1519     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1520     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1521     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1522
1523     /* Win9x: message sequence terminates here. */
1524
1525     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1526     { HCBT_SETFOCUS, hook }, /* in MDI client */
1527     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1528     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1529     { WM_SETFOCUS, sent }, /* in MDI client */
1530     { HCBT_SETFOCUS, hook },
1531     { WM_KILLFOCUS, sent }, /* in MDI client */
1532     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1533     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1534     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1535     { WM_SETFOCUS, sent|defwinproc },
1536     { WM_MDIACTIVATE, sent|defwinproc },
1537     { 0 }
1538 };
1539 /* DestroyWindow for MDI child window, initially visible */
1540 static const struct message WmDestroyMDIchildVisibleSeq[] = {
1541     { HCBT_DESTROYWND, hook },
1542     /* Win2k sends wparam set to
1543      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1544      * while Win9x doesn't bother to set child window id according to
1545      * CLIENTCREATESTRUCT.idFirstChild
1546      */
1547     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1548     { WM_SHOWWINDOW, sent|wparam, 0 },
1549     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1550     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1551     { WM_ERASEBKGND, sent|parent|optional },
1552     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1553
1554     /* { WM_DESTROY, sent }
1555      * Win9x: message sequence terminates here.
1556      */
1557
1558     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1559     { WM_KILLFOCUS, sent },
1560     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1561     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1562     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1563     { WM_SETFOCUS, sent }, /* in MDI client */
1564
1565     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1566     { WM_KILLFOCUS, sent }, /* in MDI client */
1567     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1568     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1569     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1570     { WM_SETFOCUS, sent }, /* in MDI client */
1571
1572     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1573
1574     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1575     { WM_KILLFOCUS, sent },
1576     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1577     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1578     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1579     { WM_SETFOCUS, sent }, /* in MDI client */
1580
1581     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1582     { WM_KILLFOCUS, sent }, /* in MDI client */
1583     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1584     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1585     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1586     { WM_SETFOCUS, sent }, /* in MDI client */
1587
1588     { WM_DESTROY, sent },
1589
1590     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
1591     { WM_KILLFOCUS, sent },
1592     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1593     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1594     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1595     { WM_SETFOCUS, sent }, /* in MDI client */
1596
1597     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
1598     { WM_KILLFOCUS, sent }, /* in MDI client */
1599     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1600     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1601     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1602     { WM_SETFOCUS, sent }, /* in MDI client */
1603
1604     { WM_NCDESTROY, sent },
1605     { 0 }
1606 };
1607 /* CreateWindow for MDI child window, initially invisible */
1608 static const struct message WmCreateMDIchildInvisibleSeq[] = {
1609     { HCBT_CREATEWND, hook },
1610     { WM_NCCREATE, sent }, 
1611     { WM_NCCALCSIZE, sent|wparam, 0 },
1612     { WM_CREATE, sent },
1613     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1614     { WM_SIZE, sent },
1615     { WM_MOVE, sent },
1616     /* Win2k sends wparam set to
1617      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1618      * while Win9x doesn't bother to set child window id according to
1619      * CLIENTCREATESTRUCT.idFirstChild
1620      */
1621     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1622     { 0 }
1623 };
1624 /* DestroyWindow for MDI child window, initially invisible */
1625 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
1626     { HCBT_DESTROYWND, hook },
1627     /* Win2k sends wparam set to
1628      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1629      * while Win9x doesn't bother to set child window id according to
1630      * CLIENTCREATESTRUCT.idFirstChild
1631      */
1632     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1633     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1634     { WM_DESTROY, sent },
1635     { WM_NCDESTROY, sent },
1636     { 0 }
1637 };
1638 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
1639 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
1640     { HCBT_CREATEWND, hook },
1641     { WM_NCCREATE, sent }, 
1642     { WM_NCCALCSIZE, sent|wparam, 0 },
1643     { WM_CREATE, sent },
1644     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1645     { WM_SIZE, sent },
1646     { WM_MOVE, sent },
1647     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1648     { WM_GETMINMAXINFO, sent },
1649     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1650     { WM_NCCALCSIZE, sent|wparam, 1 },
1651     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1652     { WM_SIZE, sent|defwinproc },
1653      /* in MDI frame */
1654     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1655     { WM_NCCALCSIZE, sent|wparam, 1 },
1656     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1657     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1658     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1659     /* Win2k sends wparam set to
1660      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1661      * while Win9x doesn't bother to set child window id according to
1662      * CLIENTCREATESTRUCT.idFirstChild
1663      */
1664     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1665     { WM_SHOWWINDOW, sent|wparam, 1 },
1666     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1667     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1668     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1669     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1670     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1671     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1672     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1673
1674     /* Win9x: message sequence terminates here. */
1675
1676     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1677     { HCBT_SETFOCUS, hook }, /* in MDI client */
1678     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1679     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1680     { WM_SETFOCUS, sent }, /* in MDI client */
1681     { HCBT_SETFOCUS, hook },
1682     { WM_KILLFOCUS, sent }, /* in MDI client */
1683     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1684     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1685     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1686     { WM_SETFOCUS, sent|defwinproc },
1687     { WM_MDIACTIVATE, sent|defwinproc },
1688      /* in MDI frame */
1689     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1690     { WM_NCCALCSIZE, sent|wparam, 1 },
1691     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1692     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1693     { 0 }
1694 };
1695 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
1696 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
1697     /* restore the 1st MDI child */
1698     { WM_SETREDRAW, sent|wparam, 0 },
1699     { HCBT_MINMAX, hook },
1700     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
1701     { WM_NCCALCSIZE, sent|wparam, 1 },
1702     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1703     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1704     { WM_SIZE, sent|defwinproc },
1705      /* in MDI frame */
1706     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1707     { WM_NCCALCSIZE, sent|wparam, 1 },
1708     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1709     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1710     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1711     { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
1712     /* create the 2nd MDI child */
1713     { HCBT_CREATEWND, hook },
1714     { WM_NCCREATE, sent }, 
1715     { WM_NCCALCSIZE, sent|wparam, 0 },
1716     { WM_CREATE, sent },
1717     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1718     { WM_SIZE, sent },
1719     { WM_MOVE, sent },
1720     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1721     { WM_GETMINMAXINFO, sent },
1722     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1723     { WM_NCCALCSIZE, sent|wparam, 1 },
1724     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1725     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1726     { WM_SIZE, sent|defwinproc },
1727      /* in MDI frame */
1728     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1729     { WM_NCCALCSIZE, sent|wparam, 1 },
1730     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1731     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1732     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1733     /* Win2k sends wparam set to
1734      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1735      * while Win9x doesn't bother to set child window id according to
1736      * CLIENTCREATESTRUCT.idFirstChild
1737      */
1738     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1739     { WM_SHOWWINDOW, sent|wparam, 1 },
1740     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1741     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1742     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1743     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1744     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1745     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1746
1747     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1748     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1749
1750     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1751
1752     /* Win9x: message sequence terminates here. */
1753
1754     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1755     { HCBT_SETFOCUS, hook },
1756     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
1757     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
1758     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1759     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1760     { WM_SETFOCUS, sent }, /* in MDI client */
1761     { HCBT_SETFOCUS, hook },
1762     { WM_KILLFOCUS, sent }, /* in MDI client */
1763     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1764     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1765     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1766     { WM_SETFOCUS, sent|defwinproc },
1767
1768     { WM_MDIACTIVATE, sent|defwinproc },
1769      /* in MDI frame */
1770     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1771     { WM_NCCALCSIZE, sent|wparam, 1 },
1772     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1773     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1774     { 0 }
1775 };
1776 /* WM_MDICREATE MDI child window, initially visible and maximized */
1777 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
1778     { WM_MDICREATE, sent },
1779     { HCBT_CREATEWND, hook },
1780     { WM_NCCREATE, sent }, 
1781     { WM_NCCALCSIZE, sent|wparam, 0 },
1782     { WM_CREATE, sent },
1783     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1784     { WM_SIZE, sent },
1785     { WM_MOVE, sent },
1786     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1787     { WM_GETMINMAXINFO, sent },
1788     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
1789     { WM_NCCALCSIZE, sent|wparam, 1 },
1790     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1791     { WM_SIZE, sent|defwinproc },
1792
1793      /* in MDI frame */
1794     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1795     { WM_NCCALCSIZE, sent|wparam, 1 },
1796     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1797     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1798     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1799
1800     /* Win2k sends wparam set to
1801      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
1802      * while Win9x doesn't bother to set child window id according to
1803      * CLIENTCREATESTRUCT.idFirstChild
1804      */
1805     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
1806     { WM_SHOWWINDOW, sent|wparam, 1 },
1807     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1808
1809     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1810
1811     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1812     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
1813     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1814
1815     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
1816     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1817
1818     /* Win9x: message sequence terminates here. */
1819
1820     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1821     { HCBT_SETFOCUS, hook }, /* in MDI client */
1822     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1823     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1824     { WM_SETFOCUS, sent }, /* in MDI client */
1825     { HCBT_SETFOCUS, hook },
1826     { WM_KILLFOCUS, sent }, /* in MDI client */
1827     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1828     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1829     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1830     { WM_SETFOCUS, sent|defwinproc },
1831
1832     { WM_MDIACTIVATE, sent|defwinproc },
1833
1834      /* in MDI child */
1835     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1836     { WM_NCCALCSIZE, sent|wparam, 1 },
1837     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1838     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1839
1840      /* in MDI frame */
1841     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1842     { WM_NCCALCSIZE, sent|wparam, 1 },
1843     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1844     { WM_MOVE, sent|defwinproc },
1845     { WM_SIZE, sent|defwinproc },
1846
1847      /* in MDI client */
1848     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1849     { WM_NCCALCSIZE, sent|wparam, 1 },
1850     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1851     { WM_SIZE, sent },
1852
1853      /* in MDI child */
1854     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1855     { WM_NCCALCSIZE, sent|wparam, 1 },
1856     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1857     { WM_SIZE, sent|defwinproc },
1858
1859     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1860     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
1861     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
1862     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1863     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
1864
1865     { 0 }
1866 };
1867 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
1868 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
1869     { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
1870     { HCBT_SYSCOMMAND, hook },
1871     { WM_CLOSE, sent|defwinproc },
1872     { WM_MDIDESTROY, sent }, /* in MDI client */
1873
1874     /* bring the 1st MDI child to top */
1875     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
1876     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
1877
1878     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1879
1880     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
1881     { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
1882     { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
1883
1884     /* maximize the 1st MDI child */
1885     { HCBT_MINMAX, hook },
1886     { WM_GETMINMAXINFO, sent|defwinproc },
1887     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
1888     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1889     { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
1890     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1891     { WM_SIZE, sent|defwinproc },
1892
1893     /* restore the 2nd MDI child */
1894     { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
1895     { HCBT_MINMAX, hook },
1896     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
1897     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
1898
1899     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1900
1901     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
1902     { WM_SIZE, sent|defwinproc },
1903
1904     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1905
1906     { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
1907      /* in MDI frame */
1908     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1909     { WM_NCCALCSIZE, sent|wparam, 1 },
1910     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1911     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
1912     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1913
1914     /* bring the 1st MDI child to top */
1915     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1916     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
1917     { HCBT_SETFOCUS, hook },
1918     { WM_KILLFOCUS, sent|defwinproc },
1919     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
1920     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1921     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1922     { WM_SETFOCUS, sent }, /* in MDI client */
1923     { HCBT_SETFOCUS, hook },
1924     { WM_KILLFOCUS, sent }, /* in MDI client */
1925     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1926     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1927     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1928     { WM_SETFOCUS, sent|defwinproc },
1929     { WM_MDIACTIVATE, sent|defwinproc },
1930     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1931
1932     /* apparently ShowWindow(SW_SHOW) on an MDI client */
1933     { WM_SHOWWINDOW, sent|wparam, 1 },
1934     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1935     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1936     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1937     { WM_MDIREFRESHMENU, sent },
1938
1939     { HCBT_DESTROYWND, hook },
1940     /* Win2k sends wparam set to
1941      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
1942      * while Win9x doesn't bother to set child window id according to
1943      * CLIENTCREATESTRUCT.idFirstChild
1944      */
1945     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1946     { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
1947     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1948     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1949     { WM_ERASEBKGND, sent|parent|optional },
1950     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1951
1952     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1953     { WM_DESTROY, sent|defwinproc },
1954     { WM_NCDESTROY, sent|defwinproc },
1955     { 0 }
1956 };
1957 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
1958 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
1959     { WM_MDIDESTROY, sent }, /* in MDI client */
1960     { WM_SHOWWINDOW, sent|wparam, 0 },
1961     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1962     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1963     { WM_ERASEBKGND, sent|parent|optional },
1964     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1965
1966     { HCBT_SETFOCUS, hook },
1967     { WM_KILLFOCUS, sent },
1968     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1969     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
1970     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1971     { WM_SETFOCUS, sent }, /* in MDI client */
1972     { HCBT_SETFOCUS, hook },
1973     { WM_KILLFOCUS, sent }, /* in MDI client */
1974     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
1975     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1976     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1977     { WM_SETFOCUS, sent },
1978
1979      /* in MDI child */
1980     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1981     { WM_NCCALCSIZE, sent|wparam, 1 },
1982     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1983     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
1984
1985      /* in MDI frame */
1986     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1987     { WM_NCCALCSIZE, sent|wparam, 1 },
1988     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
1989     { WM_MOVE, sent|defwinproc },
1990     { WM_SIZE, sent|defwinproc },
1991
1992      /* in MDI client */
1993     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
1994     { WM_NCCALCSIZE, sent|wparam, 1 },
1995     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
1996     { WM_SIZE, sent },
1997
1998      /* in MDI child */
1999     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
2000     { WM_NCCALCSIZE, sent|wparam, 1 },
2001     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2002     { WM_SIZE, sent|defwinproc },
2003
2004      /* in MDI child */
2005     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2006     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2007     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2008     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2009
2010      /* in MDI frame */
2011     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2012     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2013     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2014     { WM_MOVE, sent|defwinproc },
2015     { WM_SIZE, sent|defwinproc },
2016
2017      /* in MDI client */
2018     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
2019     { WM_NCCALCSIZE, sent|wparam, 1 },
2020     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
2021     { WM_SIZE, sent },
2022
2023      /* in MDI child */
2024     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOZORDER },
2025     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2026     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
2027     { WM_SIZE, sent|defwinproc },
2028     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2029     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2030
2031     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
2032
2033     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2034     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2035     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2036     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2037     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2038
2039      /* in MDI frame */
2040     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2041     { WM_NCCALCSIZE, sent|wparam, 1 },
2042     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2043     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2044
2045     { WM_NCACTIVATE, sent|wparam, 0 },
2046     { WM_MDIACTIVATE, sent },
2047
2048     { HCBT_MINMAX, hook },
2049     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
2050     { WM_NCCALCSIZE, sent|wparam, 1 },
2051
2052     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2053
2054     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2055     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE|0x8000 },
2056     { WM_SIZE, sent|defwinproc },
2057
2058      /* in MDI child */
2059     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2060     { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
2061     { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2062     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2063
2064      /* in MDI frame */
2065     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2066     { WM_NCCALCSIZE, sent|wparam, 1 },
2067     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2068     { WM_MOVE, sent|defwinproc },
2069     { WM_SIZE, sent|defwinproc },
2070
2071      /* in MDI client */
2072     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
2073     { WM_NCCALCSIZE, sent|wparam, 1 },
2074     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
2075     { WM_SIZE, sent },
2076     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2077     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2078     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
2079     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2080     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
2081
2082     { HCBT_SETFOCUS, hook },
2083     { WM_KILLFOCUS, sent },
2084     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2085     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2086     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2087     { WM_SETFOCUS, sent }, /* in MDI client */
2088
2089     { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2090
2091     { HCBT_DESTROYWND, hook },
2092     /* Win2k sends wparam set to
2093      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2094      * while Win9x doesn't bother to set child window id according to
2095      * CLIENTCREATESTRUCT.idFirstChild
2096      */
2097     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2098
2099     { WM_SHOWWINDOW, sent|wparam, 0 },
2100     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2101     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2102     { WM_ERASEBKGND, sent|parent|optional },
2103     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2104
2105     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2106     { WM_DESTROY, sent },
2107     { WM_NCDESTROY, sent },
2108     { 0 }
2109 };
2110 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
2111 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
2112     { HCBT_MINMAX, hook },
2113     { WM_GETMINMAXINFO, sent },
2114     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2115     { WM_NCCALCSIZE, sent|wparam, 1 },
2116     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2117     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2118
2119     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2120     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2121     { HCBT_SETFOCUS, hook },
2122     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2123     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2124     { WM_SETFOCUS, sent }, /* in MDI client */
2125     { HCBT_SETFOCUS, hook },
2126     { WM_KILLFOCUS, sent }, /* in MDI client */
2127     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2128     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2129     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2130     { WM_SETFOCUS, sent|defwinproc },
2131     { WM_MDIACTIVATE, sent|defwinproc },
2132     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2133     { WM_SIZE, sent|defwinproc },
2134      /* in MDI frame */
2135     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2136     { WM_NCCALCSIZE, sent|wparam, 1 },
2137     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2138     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2139     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2140     { 0 }
2141 };
2142 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
2143 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
2144     { HCBT_MINMAX, hook },
2145     { WM_GETMINMAXINFO, sent },
2146     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2147     { WM_NCCALCSIZE, sent|wparam, 1 },
2148     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2149     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2150     { WM_SIZE, sent|defwinproc },
2151      /* in MDI frame */
2152     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2153     { WM_NCCALCSIZE, sent|wparam, 1 },
2154     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|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     { 0 }
2158 };
2159 /* ShowWindow(SW_RESTORE) for a visible MDI child window */
2160 static const struct message WmRestoreMDIchildVisibleSeq[] = {
2161     { HCBT_MINMAX, hook },
2162     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
2163     { WM_NCCALCSIZE, sent|wparam, 1 },
2164     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2165     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2166     { WM_SIZE, sent|defwinproc },
2167      /* in MDI frame */
2168     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2169     { WM_NCCALCSIZE, sent|wparam, 1 },
2170     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2171     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2172     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2173     { 0 }
2174 };
2175 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
2176 static const struct message WmRestoreMDIchildInisibleSeq[] = {
2177     { HCBT_MINMAX, hook },
2178     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
2179     { WM_NCCALCSIZE, sent|wparam, 1 },
2180     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2181     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2182     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
2183     { WM_SIZE, sent|defwinproc },
2184      /* in MDI frame */
2185     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
2186     { WM_NCCALCSIZE, sent|wparam, 1 },
2187     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2188     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2189     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2190     { 0 }
2191 };
2192
2193 static HWND mdi_client;
2194 static WNDPROC old_mdi_client_proc;
2195
2196 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2197 {
2198     struct message msg;
2199
2200     /* do not log painting messages */
2201     if (message != WM_PAINT &&
2202         message != WM_ERASEBKGND &&
2203         message != WM_NCPAINT &&
2204         message != WM_NCHITTEST &&
2205         message != WM_GETTEXT &&
2206         message != WM_MDIGETACTIVE &&
2207         message != WM_GETICON &&
2208         message != WM_DEVICECHANGE)
2209     {
2210         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2211
2212         switch (message)
2213         {
2214             case WM_WINDOWPOSCHANGING:
2215             case WM_WINDOWPOSCHANGED:
2216             {
2217                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2218
2219                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2220                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2221                       winpos->hwnd, winpos->hwndInsertAfter,
2222                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2223
2224                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2225                  * in the high word for internal purposes
2226                  */
2227                 wParam = winpos->flags & 0xffff;
2228                 break;
2229             }
2230         }
2231
2232         msg.message = message;
2233         msg.flags = sent|wparam|lparam;
2234         msg.wParam = wParam;
2235         msg.lParam = lParam;
2236         add_message(&msg);
2237     }
2238
2239     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
2240 }
2241
2242 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2243 {
2244     static long defwndproc_counter = 0;
2245     LRESULT ret;
2246     struct message msg;
2247
2248     /* do not log painting messages */
2249     if (message != WM_PAINT &&
2250         message != WM_ERASEBKGND &&
2251         message != WM_NCPAINT &&
2252         message != WM_NCHITTEST &&
2253         message != WM_GETTEXT &&
2254         message != WM_GETICON &&
2255         message != WM_DEVICECHANGE)
2256     {
2257         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2258
2259         switch (message)
2260         {
2261             case WM_WINDOWPOSCHANGING:
2262             case WM_WINDOWPOSCHANGED:
2263             {
2264                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2265
2266                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2267                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2268                       winpos->hwnd, winpos->hwndInsertAfter,
2269                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2270
2271                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2272                  * in the high word for internal purposes
2273                  */
2274                 wParam = winpos->flags & 0xffff;
2275                 break;
2276             }
2277
2278             case WM_MDIACTIVATE:
2279             {
2280                 HWND active, client = GetParent(hwnd);
2281
2282                 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
2283
2284                 if (hwnd == (HWND)lParam) /* if we are being activated */
2285                     ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
2286                 else
2287                     ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
2288                 break;
2289             }
2290         }
2291
2292         msg.message = message;
2293         msg.flags = sent|wparam|lparam;
2294         if (defwndproc_counter) msg.flags |= defwinproc;
2295         msg.wParam = wParam;
2296         msg.lParam = lParam;
2297         add_message(&msg);
2298     }
2299
2300     defwndproc_counter++;
2301     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
2302     defwndproc_counter--;
2303
2304     return ret;
2305 }
2306
2307 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2308 {
2309     static long defwndproc_counter = 0;
2310     LRESULT ret;
2311     struct message msg;
2312
2313     /* do not log painting messages */
2314     if (message != WM_PAINT &&
2315         message != WM_ERASEBKGND &&
2316         message != WM_NCPAINT &&
2317         message != WM_NCHITTEST &&
2318         message != WM_GETTEXT &&
2319         message != WM_GETICON &&
2320         message != WM_DEVICECHANGE)
2321     {
2322         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2323
2324         switch (message)
2325         {
2326             case WM_WINDOWPOSCHANGING:
2327             case WM_WINDOWPOSCHANGED:
2328             {
2329                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2330
2331                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2332                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2333                       winpos->hwnd, winpos->hwndInsertAfter,
2334                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2335
2336                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2337                  * in the high word for internal purposes
2338                  */
2339                 wParam = winpos->flags & 0xffff;
2340                 break;
2341             }
2342         }
2343
2344         msg.message = message;
2345         msg.flags = sent|wparam|lparam;
2346         if (defwndproc_counter) msg.flags |= defwinproc;
2347         msg.wParam = wParam;
2348         msg.lParam = lParam;
2349         add_message(&msg);
2350     }
2351
2352     defwndproc_counter++;
2353     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
2354     defwndproc_counter--;
2355
2356     return ret;
2357 }
2358
2359 static BOOL mdi_RegisterWindowClasses(void)
2360 {
2361     WNDCLASSA cls;
2362
2363     cls.style = 0;
2364     cls.lpfnWndProc = mdi_frame_wnd_proc;
2365     cls.cbClsExtra = 0;
2366     cls.cbWndExtra = 0;
2367     cls.hInstance = GetModuleHandleA(0);
2368     cls.hIcon = 0;
2369     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2370     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2371     cls.lpszMenuName = NULL;
2372     cls.lpszClassName = "MDI_frame_class";
2373     if (!RegisterClassA(&cls)) return FALSE;
2374
2375     cls.lpfnWndProc = mdi_child_wnd_proc;
2376     cls.lpszClassName = "MDI_child_class";
2377     if (!RegisterClassA(&cls)) return FALSE;
2378
2379     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
2380     old_mdi_client_proc = cls.lpfnWndProc;
2381     cls.hInstance = GetModuleHandleA(0);
2382     cls.lpfnWndProc = mdi_client_hook_proc;
2383     cls.lpszClassName = "MDI_client_class";
2384     if (!RegisterClassA(&cls)) assert(0);
2385
2386     return TRUE;
2387 }
2388
2389 static void test_mdi_messages(void)
2390 {
2391     MDICREATESTRUCTA mdi_cs;
2392     CLIENTCREATESTRUCT client_cs;
2393     HWND mdi_frame, mdi_child, mdi_child2, active_child;
2394     BOOL zoomed;
2395     HMENU hMenu = CreateMenu();
2396
2397     assert(mdi_RegisterWindowClasses());
2398
2399     flush_sequence();
2400
2401     trace("creating MDI frame window\n");
2402     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
2403                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2404                                 WS_MAXIMIZEBOX | WS_VISIBLE,
2405                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
2406                                 GetDesktopWindow(), hMenu,
2407                                 GetModuleHandleA(0), NULL);
2408     assert(mdi_frame);
2409     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
2410
2411     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2412     ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
2413
2414     trace("creating MDI client window\n");
2415     client_cs.hWindowMenu = 0;
2416     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
2417     mdi_client = CreateWindowExA(0, "MDI_client_class",
2418                                  NULL,
2419                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
2420                                  0, 0, 0, 0,
2421                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
2422     assert(mdi_client);
2423     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
2424
2425     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2426     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
2427
2428     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2429     ok(!active_child, "wrong active MDI child %p\n", active_child);
2430     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2431
2432     SetFocus(0);
2433     flush_sequence();
2434
2435     trace("creating invisible MDI child window\n");
2436     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2437                                 WS_CHILD,
2438                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2439                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2440     assert(mdi_child);
2441
2442     flush_sequence();
2443     ShowWindow(mdi_child, SW_SHOWNORMAL);
2444     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
2445
2446     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2447     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2448
2449     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2450     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2451
2452     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2453     ok(!active_child, "wrong active MDI child %p\n", active_child);
2454     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2455
2456     ShowWindow(mdi_child, SW_HIDE);
2457     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
2458     flush_sequence();
2459
2460     ShowWindow(mdi_child, SW_SHOW);
2461     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
2462
2463     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2464     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2465
2466     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2467     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2468
2469     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2470     ok(!active_child, "wrong active MDI child %p\n", active_child);
2471     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2472
2473     DestroyWindow(mdi_child);
2474     flush_sequence();
2475
2476     trace("creating visible MDI child window\n");
2477     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2478                                 WS_CHILD | WS_VISIBLE,
2479                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2480                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2481     assert(mdi_child);
2482     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
2483
2484     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2485     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
2486
2487     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2488     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2489
2490     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2491     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2492     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2493     flush_sequence();
2494
2495     DestroyWindow(mdi_child);
2496     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2497
2498     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2499     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2500
2501     /* Win2k: MDI client still returns a just destroyed child as active
2502      * Win9x: MDI client returns 0
2503      */
2504     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2505     ok(active_child == mdi_child || /* win2k */
2506        !active_child, /* win9x */
2507        "wrong active MDI child %p\n", active_child);
2508     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2509
2510     flush_sequence();
2511
2512     trace("creating invisible MDI child window\n");
2513     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2514                                 WS_CHILD,
2515                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2516                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2517     assert(mdi_child2);
2518     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
2519
2520     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
2521     ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
2522
2523     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2524     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2525
2526     /* Win2k: MDI client still returns a just destroyed child as active
2527      * Win9x: MDI client returns mdi_child2
2528      */
2529     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2530     ok(active_child == mdi_child || /* win2k */
2531        active_child == mdi_child2, /* win9x */
2532        "wrong active MDI child %p\n", active_child);
2533     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2534     flush_sequence();
2535
2536     ShowWindow(mdi_child2, SW_MAXIMIZE);
2537     ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
2538
2539     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2540     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2541
2542     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2543     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2544     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2545     flush_sequence();
2546
2547     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2548     ok(GetFocus() == mdi_child2 || /* win2k */
2549        GetFocus() == 0, /* win9x */
2550        "wrong focus window %p\n", GetFocus());
2551
2552     SetFocus(0);
2553     flush_sequence();
2554
2555     ShowWindow(mdi_child2, SW_HIDE);
2556     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2557
2558     ShowWindow(mdi_child2, SW_RESTORE);
2559     ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
2560     flush_sequence();
2561
2562     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
2563     ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
2564
2565     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2566     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2567     ok(!zoomed, "wrong zoomed state %d\n", zoomed);
2568     flush_sequence();
2569
2570     SetFocus(0);
2571     flush_sequence();
2572
2573     ShowWindow(mdi_child2, SW_HIDE);
2574     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2575
2576     ShowWindow(mdi_child2, SW_SHOW);
2577     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
2578
2579     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2580     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2581
2582     ShowWindow(mdi_child2, SW_MAXIMIZE);
2583     ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
2584
2585     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2586     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2587
2588     ShowWindow(mdi_child2, SW_RESTORE);
2589     ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
2590
2591     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2592     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2593
2594     SetFocus(0);
2595     flush_sequence();
2596
2597     ShowWindow(mdi_child2, SW_HIDE);
2598     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
2599
2600     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2601     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2602
2603     DestroyWindow(mdi_child2);
2604     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
2605
2606     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2607     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2608
2609     /* test for maximized MDI children */
2610     trace("creating maximized visible MDI child window 1\n");
2611     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2612                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2613                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2614                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2615     assert(mdi_child);
2616     ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
2617     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2618
2619     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2620     ok(GetFocus() == mdi_child || /* win2k */
2621        GetFocus() == 0, /* win9x */
2622        "wrong focus window %p\n", GetFocus());
2623
2624     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2625     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2626     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2627     flush_sequence();
2628
2629     trace("creating maximized visible MDI child window 2\n");
2630     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2631                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2632                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2633                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2634     assert(mdi_child2);
2635     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2636     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2637     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2638
2639     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2640     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2641
2642     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2643     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2644     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2645     flush_sequence();
2646
2647     trace("destroying maximized visible MDI child window 2\n");
2648     DestroyWindow(mdi_child2);
2649     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2650
2651     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2652
2653     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2654     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2655
2656     /* Win2k: MDI client still returns a just destroyed child as active
2657      * Win9x: MDI client returns 0
2658      */
2659     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2660     ok(active_child == mdi_child2 || /* win2k */
2661        !active_child, /* win9x */
2662        "wrong active MDI child %p\n", active_child);
2663     flush_sequence();
2664
2665     ShowWindow(mdi_child, SW_MAXIMIZE);
2666     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2667     flush_sequence();
2668
2669     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2670     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2671
2672     trace("re-creating maximized visible MDI child window 2\n");
2673     mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
2674                                 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
2675                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
2676                                 mdi_client, 0, GetModuleHandleA(0), NULL);
2677     assert(mdi_child2);
2678     ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
2679     ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
2680     ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
2681
2682     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2683     ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
2684
2685     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2686     ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
2687     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2688     flush_sequence();
2689
2690     SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
2691     ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
2692     ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
2693
2694     ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
2695     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2696     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2697
2698     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2699     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2700     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2701     flush_sequence();
2702
2703     DestroyWindow(mdi_child);
2704     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
2705
2706     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2707     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2708
2709     /* Win2k: MDI client still returns a just destroyed child as active
2710      * Win9x: MDI client returns 0
2711      */
2712     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2713     ok(active_child == mdi_child || /* win2k */
2714        !active_child, /* win9x */
2715        "wrong active MDI child %p\n", active_child);
2716     flush_sequence();
2717     /* end of test for maximized MDI children */
2718
2719     mdi_cs.szClass = "MDI_child_Class";
2720     mdi_cs.szTitle = "MDI child";
2721     mdi_cs.hOwner = GetModuleHandleA(0);
2722     mdi_cs.x = 0;
2723     mdi_cs.y = 0;
2724     mdi_cs.cx = CW_USEDEFAULT;
2725     mdi_cs.cy = CW_USEDEFAULT;
2726     mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
2727     mdi_cs.lParam = 0;
2728     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
2729     ok(mdi_child != 0, "MDI child creation failed\n");
2730     ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
2731
2732     ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
2733
2734     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2735     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2736
2737     ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
2738     ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
2739     ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
2740
2741     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2742     ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
2743     ok(zoomed, "wrong zoomed state %d\n", zoomed);
2744     flush_sequence();
2745
2746     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
2747     ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
2748
2749     ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
2750     active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
2751     ok(!active_child, "wrong active MDI child %p\n", active_child);
2752
2753     SetFocus(0);
2754     flush_sequence();
2755
2756     DestroyWindow(mdi_client);
2757     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
2758
2759     DestroyWindow(mdi_frame);
2760     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
2761 }
2762 /************************* End of MDI test **********************************/
2763
2764 static void test_WM_SETREDRAW(HWND hwnd)
2765 {
2766     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
2767
2768     flush_sequence();
2769
2770     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
2771     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
2772
2773     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
2774     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
2775
2776     flush_sequence();
2777     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
2778     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
2779
2780     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
2781     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
2782
2783     /* restore original WS_VISIBLE state */
2784     SetWindowLongA(hwnd, GWL_STYLE, style);
2785
2786     flush_sequence();
2787 }
2788
2789 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2790 {
2791     struct message msg;
2792
2793     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2794
2795     /* explicitly ignore WM_GETICON message */
2796     if (message == WM_GETICON) return 0;
2797
2798     switch (message)
2799     {
2800         case WM_WINDOWPOSCHANGING:
2801         case WM_WINDOWPOSCHANGED:
2802         {
2803             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
2804
2805             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
2806             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
2807                   winpos->hwnd, winpos->hwndInsertAfter,
2808                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
2809
2810             /* Log only documented flags, win2k uses 0x1000 and 0x2000
2811              * in the high word for internal purposes
2812              */
2813             wParam = winpos->flags & 0xffff;
2814             break;
2815         }
2816     }
2817
2818     msg.message = message;
2819     msg.flags = sent|wparam|lparam;
2820     msg.wParam = wParam;
2821     msg.lParam = lParam;
2822     add_message(&msg);
2823
2824     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
2825     if (message == WM_TIMER) EndDialog( hwnd, 0 );
2826     return 0;
2827 }
2828
2829 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2830 {
2831     DWORD style, exstyle;
2832     INT xmin, xmax;
2833     BOOL ret;
2834
2835     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2836     style = GetWindowLongA(hwnd, GWL_STYLE);
2837     /* do not be confused by WS_DLGFRAME set */
2838     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2839
2840     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2841     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2842
2843     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
2844     ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2845     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2846         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
2847     else
2848         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
2849
2850     style = GetWindowLongA(hwnd, GWL_STYLE);
2851     if (set) ok(style & set, "style %08lx should be set\n", set);
2852     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2853
2854     /* a subsequent call should do nothing */
2855     ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
2856     ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
2857     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
2858
2859     xmin = 0xdeadbeef;
2860     xmax = 0xdeadbeef;
2861     trace("Ignore GetScrollRange error below if you are on Win9x\n");
2862     ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
2863     ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
2864     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
2865     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
2866     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
2867 }
2868
2869 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
2870 {
2871     DWORD style, exstyle;
2872     SCROLLINFO si;
2873     BOOL ret;
2874
2875     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
2876     style = GetWindowLongA(hwnd, GWL_STYLE);
2877     /* do not be confused by WS_DLGFRAME set */
2878     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
2879
2880     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
2881     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
2882
2883     si.cbSize = sizeof(si);
2884     si.fMask = SIF_RANGE;
2885     si.nMin = min;
2886     si.nMax = max;
2887     SetScrollInfo(hwnd, ctl, &si, TRUE);
2888     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
2889         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
2890     else
2891         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
2892
2893     style = GetWindowLongA(hwnd, GWL_STYLE);
2894     if (set) ok(style & set, "style %08lx should be set\n", set);
2895     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
2896
2897     /* a subsequent call should do nothing */
2898     SetScrollInfo(hwnd, ctl, &si, TRUE);
2899     if (style & WS_HSCROLL)
2900         ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2901     else if (style & WS_VSCROLL)
2902         ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2903     else
2904         ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2905
2906     si.fMask = SIF_PAGE;
2907     si.nPage = 5;
2908     SetScrollInfo(hwnd, ctl, &si, FALSE);
2909     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2910
2911     si.fMask = SIF_POS;
2912     si.nPos = max - 1;
2913     SetScrollInfo(hwnd, ctl, &si, FALSE);
2914     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
2915
2916     si.fMask = SIF_RANGE;
2917     si.nMin = 0xdeadbeef;
2918     si.nMax = 0xdeadbeef;
2919     ret = GetScrollInfo(hwnd, ctl, &si);
2920     ok( ret, "GetScrollInfo error %ld\n", GetLastError());
2921     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
2922     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
2923     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
2924 }
2925
2926 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
2927 static void test_scroll_messages(HWND hwnd)
2928 {
2929     SCROLLINFO si;
2930     INT min, max;
2931     BOOL ret;
2932
2933     min = 0xdeadbeef;
2934     max = 0xdeadbeef;
2935     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
2936     ok( ret, "GetScrollRange error %ld\n", GetLastError());
2937     if (sequence->message != WmGetScrollRangeSeq[0].message)
2938         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2939     /* values of min and max are undefined */
2940     flush_sequence();
2941
2942     ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
2943     ok( ret, "SetScrollRange error %ld\n", GetLastError());
2944     if (sequence->message != WmSetScrollRangeSeq[0].message)
2945         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2946     flush_sequence();
2947
2948     min = 0xdeadbeef;
2949     max = 0xdeadbeef;
2950     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
2951     ok( ret, "GetScrollRange error %ld\n", GetLastError());
2952     if (sequence->message != WmGetScrollRangeSeq[0].message)
2953         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
2954     /* values of min and max are undefined */
2955     flush_sequence();
2956
2957     si.cbSize = sizeof(si);
2958     si.fMask = SIF_RANGE;
2959     si.nMin = 20;
2960     si.nMax = 160;
2961     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2962     if (sequence->message != WmSetScrollRangeSeq[0].message)
2963         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2964     flush_sequence();
2965
2966     si.fMask = SIF_PAGE;
2967     si.nPage = 10;
2968     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2969     if (sequence->message != WmSetScrollRangeSeq[0].message)
2970         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2971     flush_sequence();
2972
2973     si.fMask = SIF_POS;
2974     si.nPos = 20;
2975     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
2976     if (sequence->message != WmSetScrollRangeSeq[0].message)
2977         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2978     flush_sequence();
2979
2980     si.fMask = SIF_RANGE;
2981     si.nMin = 0xdeadbeef;
2982     si.nMax = 0xdeadbeef;
2983     ret = GetScrollInfo(hwnd, SB_CTL, &si);
2984     ok( ret, "GetScrollInfo error %ld\n", GetLastError());
2985     if (sequence->message != WmGetScrollInfoSeq[0].message)
2986         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
2987     /* values of min and max are undefined */
2988     flush_sequence();
2989
2990     /* set WS_HSCROLL */
2991     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2992     /* clear WS_HSCROLL */
2993     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2994
2995     /* set WS_HSCROLL */
2996     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
2997     /* clear WS_HSCROLL */
2998     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
2999
3000     /* set WS_VSCROLL */
3001     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3002     /* clear WS_VSCROLL */
3003     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3004
3005     /* set WS_VSCROLL */
3006     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
3007     /* clear WS_VSCROLL */
3008     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
3009 }
3010
3011 static void test_showwindow(void)
3012 {
3013     HWND hwnd, hchild;
3014     RECT rc;
3015
3016     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3017                            100, 100, 200, 200, 0, 0, 0, NULL);
3018     ok (hwnd != 0, "Failed to create overlapped window\n");
3019     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3020                              0, 0, 10, 10, hwnd, 0, 0, NULL);
3021     ok (hchild != 0, "Failed to create child\n");
3022     flush_sequence();
3023
3024     /* ShowWindow( SW_SHOWNA) for invisible top level window */
3025     trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
3026     ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3027     ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
3028     trace("done\n");
3029
3030     /* ShowWindow( SW_SHOWNA) for now visible top level window */
3031     trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
3032     ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3033     ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
3034     trace("done\n");
3035     /* back to invisible */
3036     ShowWindow(hchild, SW_HIDE);
3037     ShowWindow(hwnd, SW_HIDE);
3038     flush_sequence();
3039     /* ShowWindow(SW_SHOWNA) with child and parent invisible */ 
3040     trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
3041     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3042     ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
3043     trace("done\n");
3044     /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ 
3045     ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
3046     flush_sequence();
3047     trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
3048     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3049     ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
3050     trace("done\n");
3051     /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
3052     ShowWindow( hwnd, SW_SHOW);
3053     flush_sequence();
3054     trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
3055     ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
3056     ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
3057     trace("done\n");
3058
3059     /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
3060     ShowWindow( hchild, SW_HIDE);
3061     flush_sequence();
3062     trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
3063     ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
3064     ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
3065     trace("done\n");
3066
3067     SetCapture(hchild);
3068     ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
3069     DestroyWindow(hchild);
3070     ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
3071
3072     DestroyWindow(hwnd);
3073     flush_sequence();
3074
3075     /* Popup windows */
3076     /* Test 1:
3077      * 1. Create invisible maximized popup window.
3078      * 2. Move and resize it.
3079      * 3. Show it maximized.
3080      */
3081     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3082     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3083                            100, 100, 200, 200, 0, 0, 0, NULL);
3084     ok (hwnd != 0, "Failed to create popup window\n");
3085     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3086     trace("done\n");
3087
3088     GetWindowRect(hwnd, &rc);
3089     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3090         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3091         "Invalid maximized size before ShowWindow (%ld,%ld)-(%ld,%ld)\n",
3092         rc.left, rc.top, rc.right, rc.bottom);
3093     /* Reset window's size & position */
3094     SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
3095     flush_sequence();
3096
3097     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible popup window\n");
3098     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3099     ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3100     trace("done\n");
3101
3102     GetWindowRect(hwnd, &rc);
3103     ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
3104         rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
3105         "Invalid maximized size after ShowWindow (%ld,%ld)-(%ld,%ld)\n",
3106         rc.left, rc.top, rc.right, rc.bottom);
3107     DestroyWindow(hwnd);
3108     flush_sequence();
3109
3110     /* Test 2:
3111      * 1. Create invisible maximized popup window.
3112      * 2. Show it maximized.
3113      */
3114     trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
3115     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
3116                            100, 100, 200, 200, 0, 0, 0, NULL);
3117     ok (hwnd != 0, "Failed to create popup window\n");
3118     ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3119     trace("done\n");
3120
3121     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible popup window\n");
3122     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3123     ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
3124     trace("done\n");
3125     DestroyWindow(hwnd);
3126     flush_sequence();
3127
3128     /* Test 3:
3129      * 1. Create visible maximized popup window.
3130      */
3131     trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
3132     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3133                            100, 100, 200, 200, 0, 0, 0, NULL);
3134     ok (hwnd != 0, "Failed to create popup window\n");
3135     ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
3136     trace("done\n");
3137     DestroyWindow(hwnd);
3138     flush_sequence();
3139
3140     /* Test 4:
3141      * 1. Create visible popup window.
3142      * 2. Maximize it.
3143      */
3144     trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
3145     hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
3146                            100, 100, 200, 200, 0, 0, 0, NULL);
3147     ok (hwnd != 0, "Failed to create popup window\n");
3148     ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", TRUE);
3149     trace("done\n");
3150
3151     trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
3152     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3153     ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", TRUE);
3154     trace("done\n");
3155     DestroyWindow(hwnd);
3156     flush_sequence();
3157 }
3158
3159 static void test_sys_menu(HWND hwnd)
3160 {
3161     HMENU hmenu;
3162     UINT state;
3163
3164     /* test existing window without CS_NOCLOSE style */
3165     hmenu = GetSystemMenu(hwnd, FALSE);
3166     ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
3167
3168     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3169     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3170     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3171
3172     EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
3173     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3174
3175     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3176     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3177     ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
3178
3179     EnableMenuItem(hmenu, SC_CLOSE, 0);
3180     ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
3181
3182     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3183     ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3184     ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
3185
3186     /* test new window with CS_NOCLOSE style */
3187     hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3188                            100, 100, 200, 200, 0, 0, 0, NULL);
3189     ok (hwnd != 0, "Failed to create overlapped window\n");
3190
3191     hmenu = GetSystemMenu(hwnd, FALSE);
3192     ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
3193
3194     state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
3195     ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
3196
3197     DestroyWindow(hwnd);
3198 }
3199
3200 /* test if we receive the right sequence of messages */
3201 static void test_messages(void)
3202 {
3203     HWND hwnd, hparent, hchild;
3204     HWND hchild2, hbutton;
3205     HMENU hmenu;
3206     MSG msg;
3207     DWORD ret;
3208
3209     flush_sequence();
3210
3211     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3212                            100, 100, 200, 200, 0, 0, 0, NULL);
3213     ok (hwnd != 0, "Failed to create overlapped window\n");
3214     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3215
3216     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
3217     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
3218     ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
3219
3220     /* test WM_SETREDRAW on a not visible top level window */
3221     test_WM_SETREDRAW(hwnd);
3222
3223     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3224     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
3225     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
3226
3227     ok(GetActiveWindow() == hwnd, "window should be active\n");
3228     ok(GetFocus() == hwnd, "window should have input focus\n");
3229     ShowWindow(hwnd, SW_HIDE);
3230     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
3231
3232     ShowWindow(hwnd, SW_SHOW);
3233     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
3234
3235     ShowWindow(hwnd, SW_HIDE);
3236     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
3237
3238     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
3239     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
3240
3241     ShowWindow(hwnd, SW_RESTORE);
3242     /* FIXME: add ok_sequence() here */
3243     flush_sequence();
3244
3245     ShowWindow(hwnd, SW_SHOW);
3246     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
3247
3248     ok(GetActiveWindow() == hwnd, "window should be active\n");
3249     ok(GetFocus() == hwnd, "window should have input focus\n");
3250     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3251     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
3252     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
3253     ok(GetActiveWindow() == hwnd, "window should still be active\n");
3254
3255     /* test WM_SETREDRAW on a visible top level window */
3256     ShowWindow(hwnd, SW_SHOW);
3257     test_WM_SETREDRAW(hwnd);
3258
3259     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
3260     test_scroll_messages(hwnd);
3261
3262     /* test resizing and moving */
3263     SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
3264     ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
3265     SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );
3266     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
3267
3268     /* popups don't get WM_GETMINMAXINFO */
3269     SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
3270     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
3271     flush_sequence();
3272     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
3273     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
3274
3275     test_sys_menu(hwnd);
3276
3277     flush_sequence();
3278     DestroyWindow(hwnd);
3279     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
3280
3281     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3282                               100, 100, 200, 200, 0, 0, 0, NULL);
3283     ok (hparent != 0, "Failed to create parent window\n");
3284     flush_sequence();
3285
3286     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
3287                              0, 0, 10, 10, hparent, 0, 0, NULL);
3288     ok (hchild != 0, "Failed to create child window\n");
3289     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
3290     DestroyWindow(hchild);
3291     flush_sequence();
3292
3293     /* visible child window with a caption */
3294     hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
3295                              WS_CHILD | WS_VISIBLE | WS_CAPTION,
3296                              0, 0, 10, 10, hparent, 0, 0, NULL);
3297     ok (hchild != 0, "Failed to create child window\n");
3298     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
3299
3300     trace("testing scroll APIs on a visible child window %p\n", hchild);
3301     test_scroll_messages(hchild);
3302
3303     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3304     ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
3305
3306     DestroyWindow(hchild);
3307     flush_sequence();
3308
3309     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3310                              0, 0, 10, 10, hparent, 0, 0, NULL);
3311     ok (hchild != 0, "Failed to create child window\n");
3312     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
3313     
3314     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
3315                                100, 100, 50, 50, hparent, 0, 0, NULL);
3316     ok (hchild2 != 0, "Failed to create child2 window\n");
3317     flush_sequence();
3318
3319     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
3320                               0, 100, 50, 50, hchild, 0, 0, NULL);
3321     ok (hbutton != 0, "Failed to create button window\n");
3322
3323     /* test WM_SETREDRAW on a not visible child window */
3324     test_WM_SETREDRAW(hchild);
3325
3326     ShowWindow(hchild, SW_SHOW);
3327     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
3328
3329     ShowWindow(hchild, SW_HIDE);
3330     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
3331
3332     ShowWindow(hchild, SW_SHOW);
3333     ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
3334
3335     /* test WM_SETREDRAW on a visible child window */
3336     test_WM_SETREDRAW(hchild);
3337
3338     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
3339     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
3340
3341     ShowWindow(hchild, SW_HIDE);
3342     flush_sequence();
3343     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3344     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
3345
3346     ShowWindow(hchild, SW_HIDE);
3347     flush_sequence();
3348     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
3349     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
3350
3351     /* DestroyWindow sequence below expects that a child has focus */
3352     SetFocus(hchild);
3353     flush_sequence();
3354
3355     DestroyWindow(hchild);
3356     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
3357     DestroyWindow(hchild2);
3358     DestroyWindow(hbutton);
3359
3360     flush_sequence();
3361     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
3362                              0, 0, 100, 100, hparent, 0, 0, NULL);
3363     ok (hchild != 0, "Failed to create child popup window\n");
3364     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
3365     DestroyWindow(hchild);
3366
3367     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
3368     flush_sequence();
3369     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
3370                              0, 0, 100, 100, hparent, 0, 0, NULL);
3371     ok (hchild != 0, "Failed to create popup window\n");
3372     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
3373     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3374     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
3375     flush_sequence();
3376     ShowWindow(hchild, SW_SHOW);
3377     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
3378     flush_sequence();
3379     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3380     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
3381     flush_sequence();
3382     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
3383     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
3384     DestroyWindow(hchild);
3385
3386     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
3387      * changes nothing in message sequences.
3388      */
3389     flush_sequence();
3390     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
3391                              0, 0, 100, 100, hparent, 0, 0, NULL);
3392     ok (hchild != 0, "Failed to create popup window\n");
3393     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
3394     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3395     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
3396     flush_sequence();
3397     ShowWindow(hchild, SW_SHOW);
3398     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
3399     flush_sequence();
3400     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3401     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
3402     DestroyWindow(hchild);
3403
3404     flush_sequence();
3405     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
3406                            0, 0, 100, 100, hparent, 0, 0, NULL);
3407     ok(hwnd != 0, "Failed to create custom dialog window\n");
3408     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
3409
3410     /*
3411     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
3412     test_scroll_messages(hwnd);
3413     */
3414
3415     flush_sequence();
3416     after_end_dialog = 1;
3417     EndDialog( hwnd, 0 );
3418     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
3419
3420     DestroyWindow(hwnd);
3421     after_end_dialog = 0;
3422
3423     hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
3424                            0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
3425     ok(hwnd != 0, "Failed to create custom dialog window\n");
3426     flush_sequence();
3427     trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
3428     ShowWindow(hwnd, SW_SHOW);
3429     ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
3430     DestroyWindow(hwnd);
3431
3432     flush_sequence();
3433     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
3434     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
3435
3436     /* test showing child with hidden parent */
3437     ShowWindow( hparent, SW_HIDE );
3438     flush_sequence();
3439
3440     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
3441                              0, 0, 10, 10, hparent, 0, 0, NULL);
3442     ok (hchild != 0, "Failed to create child window\n");
3443     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
3444
3445     ShowWindow( hchild, SW_SHOW );
3446     ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", FALSE);
3447     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3448     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3449
3450     ShowWindow( hchild, SW_HIDE );
3451     ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
3452     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
3453     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3454
3455     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3456     ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", FALSE);
3457     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
3458     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3459
3460     SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3461     ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
3462     ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
3463     ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
3464
3465     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
3466     flush_sequence();
3467     DestroyWindow(hchild);
3468     ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
3469
3470     DestroyWindow(hparent);
3471     flush_sequence();
3472
3473     /* Message sequence for SetMenu */
3474     ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
3475     ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
3476
3477     hmenu = CreateMenu();
3478     ok (hmenu != 0, "Failed to create menu\n");
3479     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
3480     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3481                            100, 100, 200, 200, 0, hmenu, 0, NULL);
3482     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
3483     ok (SetMenu(hwnd, 0), "SetMenu\n");
3484     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
3485     ok (SetMenu(hwnd, 0), "SetMenu\n");
3486     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
3487     ShowWindow(hwnd, SW_SHOW);
3488     UpdateWindow( hwnd );
3489     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3490     flush_sequence();
3491     ok (SetMenu(hwnd, 0), "SetMenu\n");
3492     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
3493     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
3494     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
3495
3496     UpdateWindow( hwnd );
3497     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3498     flush_sequence();
3499     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
3500     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3501     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
3502
3503     DestroyWindow(hwnd);
3504     flush_sequence();
3505
3506     /* Message sequence for EnableWindow */
3507     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3508                               100, 100, 200, 200, 0, 0, 0, NULL);
3509     ok (hparent != 0, "Failed to create parent window\n");
3510     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
3511                              0, 0, 10, 10, hparent, 0, 0, NULL);
3512     ok (hchild != 0, "Failed to create child window\n");
3513
3514     SetFocus(hchild);
3515     flush_sequence();
3516
3517     EnableWindow(hparent, FALSE);
3518     ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
3519
3520     EnableWindow(hparent, TRUE);
3521     ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
3522
3523     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3524     flush_sequence();
3525
3526     /* MsgWaitForMultipleObjects test */
3527     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3528     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
3529
3530     PostMessageA(hparent, WM_USER, 0, 0);
3531
3532     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3533     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
3534
3535     ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
3536     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
3537
3538     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
3539     ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
3540     /* end of MsgWaitForMultipleObjects test */
3541
3542     /* the following test causes an exception in user.exe under win9x */
3543     if (!PostMessageW( hparent, WM_USER, 0, 0 )) return;
3544     PostMessageW( hparent, WM_USER+1, 0, 0 );
3545     /* PeekMessage(NULL) fails, but still removes the message */
3546     SetLastError(0xdeadbeef);
3547     ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
3548     ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
3549         GetLastError() == 0xdeadbeef, /* NT4 */
3550         "last error is %ld\n", GetLastError() );
3551     ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
3552     ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
3553
3554     DestroyWindow(hchild);
3555     DestroyWindow(hparent);
3556     flush_sequence();
3557
3558     test_showwindow();
3559 }
3560
3561 /****************** button message test *************************/
3562 static const struct message WmSetFocusButtonSeq[] =
3563 {
3564     { HCBT_SETFOCUS, hook },
3565     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3566     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3567     { WM_SETFOCUS, sent|wparam, 0 },
3568     { WM_CTLCOLORBTN, sent|defwinproc },
3569     { 0 }
3570 };
3571 static const struct message WmKillFocusButtonSeq[] =
3572 {
3573     { HCBT_SETFOCUS, hook },
3574     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3575     { WM_KILLFOCUS, sent|wparam, 0 },
3576     { WM_CTLCOLORBTN, sent|defwinproc },
3577     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3578     { 0 }
3579 };
3580 static const struct message WmSetFocusStaticSeq[] =
3581 {
3582     { HCBT_SETFOCUS, hook },
3583     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3584     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3585     { WM_SETFOCUS, sent|wparam, 0 },
3586     { WM_CTLCOLORSTATIC, sent|defwinproc },
3587     { 0 }
3588 };
3589 static const struct message WmKillFocusStaticSeq[] =
3590 {
3591     { HCBT_SETFOCUS, hook },
3592     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3593     { WM_KILLFOCUS, sent|wparam, 0 },
3594     { WM_CTLCOLORSTATIC, sent|defwinproc },
3595     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3596     { 0 }
3597 };
3598 static const struct message WmLButtonDownSeq[] =
3599 {
3600     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
3601     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
3602     { HCBT_SETFOCUS, hook },
3603     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3604     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3605     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
3606     { WM_CTLCOLORBTN, sent|defwinproc },
3607     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
3608     { WM_CTLCOLORBTN, sent|defwinproc },
3609     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3610     { 0 }
3611 };
3612 static const struct message WmLButtonUpSeq[] =
3613 {
3614     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
3615     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
3616     { WM_CTLCOLORBTN, sent|defwinproc },
3617     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3618     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
3619     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
3620     { 0 }
3621 };
3622
3623 static WNDPROC old_button_proc;
3624
3625 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3626 {
3627     static long defwndproc_counter = 0;
3628     LRESULT ret;
3629     struct message msg;
3630
3631     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
3632
3633     /* explicitly ignore WM_GETICON message */
3634     if (message == WM_GETICON) return 0;
3635
3636     msg.message = message;
3637     msg.flags = sent|wparam|lparam;
3638     if (defwndproc_counter) msg.flags |= defwinproc;
3639     msg.wParam = wParam;
3640     msg.lParam = lParam;
3641     add_message(&msg);
3642
3643     if (message == BM_SETSTATE)
3644         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
3645
3646     defwndproc_counter++;
3647     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
3648     defwndproc_counter--;
3649
3650     return ret;
3651 }
3652
3653 static void subclass_button(void)
3654 {
3655     WNDCLASSA cls;
3656
3657     if (!GetClassInfoA(0, "button", &cls)) assert(0);
3658
3659     old_button_proc = cls.lpfnWndProc;
3660
3661     cls.hInstance = GetModuleHandle(0);
3662     cls.lpfnWndProc = button_hook_proc;
3663     cls.lpszClassName = "my_button_class";
3664     if (!RegisterClassA(&cls)) assert(0);
3665 }
3666
3667 static void test_button_messages(void)
3668 {
3669     static const struct
3670     {
3671         DWORD style;
3672         DWORD dlg_code;
3673         const struct message *setfocus;
3674         const struct message *killfocus;
3675     } button[] = {
3676         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
3677           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
3678         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
3679           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
3680         { BS_CHECKBOX, DLGC_BUTTON,
3681           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3682         { BS_AUTOCHECKBOX, DLGC_BUTTON,
3683           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3684         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
3685           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3686         { BS_3STATE, DLGC_BUTTON,
3687           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3688         { BS_AUTO3STATE, DLGC_BUTTON,
3689           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3690         { BS_GROUPBOX, DLGC_STATIC,
3691           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3692         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
3693           WmSetFocusButtonSeq, WmKillFocusButtonSeq },
3694         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
3695           WmSetFocusStaticSeq, WmKillFocusStaticSeq },
3696         { BS_OWNERDRAW, DLGC_BUTTON,
3697           WmSetFocusButtonSeq, WmKillFocusButtonSeq }
3698     };
3699     unsigned int i;
3700     HWND hwnd;
3701     DWORD dlg_code;
3702
3703     subclass_button();
3704
3705     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
3706     {
3707         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
3708                                0, 0, 50, 14, 0, 0, 0, NULL);
3709         ok(hwnd != 0, "Failed to create button window\n");
3710
3711         dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
3712         ok(dlg_code == button[i].dlg_code, "%d: wrong dlg_code %08lx\n", i, dlg_code);
3713
3714         ShowWindow(hwnd, SW_SHOW);
3715         UpdateWindow(hwnd);
3716         SetFocus(0);
3717         flush_sequence();
3718
3719         trace("button style %08lx\n", button[i].style);
3720         SetFocus(hwnd);
3721         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
3722
3723         SetFocus(0);
3724         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
3725
3726         DestroyWindow(hwnd);
3727     }
3728
3729     hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
3730                            0, 0, 50, 14, 0, 0, 0, NULL);
3731     ok(hwnd != 0, "Failed to create button window\n");
3732
3733     SetFocus(0);
3734     flush_sequence();
3735
3736     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
3737     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
3738
3739     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
3740     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
3741     DestroyWindow(hwnd);
3742 }
3743
3744 /************* painting message test ********************/
3745
3746 void dump_region(HRGN hrgn)
3747 {
3748     DWORD i, size;
3749     RGNDATA *data = NULL;
3750     RECT *rect;
3751
3752     if (!hrgn)
3753     {
3754         printf( "null region\n" );
3755         return;
3756     }
3757     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
3758     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
3759     GetRegionData( hrgn, size, data );
3760     printf("%ld rects:", data->rdh.nCount );
3761     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
3762         printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
3763     printf("\n");
3764     HeapFree( GetProcessHeap(), 0, data );
3765 }
3766
3767 static void check_update_rgn( HWND hwnd, HRGN hrgn )
3768 {
3769     INT ret;
3770     RECT r1, r2;
3771     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
3772     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
3773
3774     ret = GetUpdateRgn( hwnd, update, FALSE );
3775     ok( ret != ERROR, "GetUpdateRgn failed\n" );
3776     if (ret == NULLREGION)
3777     {
3778         ok( !hrgn, "Update region shouldn't be empty\n" );
3779     }
3780     else
3781     {
3782         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
3783         {
3784             ok( 0, "Regions are different\n" );
3785             if (winetest_debug > 0)
3786             {
3787                 printf( "Update region: " );
3788                 dump_region( update );
3789                 printf( "Wanted region: " );
3790                 dump_region( hrgn );
3791             }
3792         }
3793     }
3794     GetRgnBox( update, &r1 );
3795     GetUpdateRect( hwnd, &r2, FALSE );
3796     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
3797         "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
3798         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
3799
3800     DeleteObject( tmp );
3801     DeleteObject( update );
3802 }
3803
3804 static const struct message WmInvalidateRgn[] = {
3805     { WM_NCPAINT, sent },
3806     { WM_GETTEXT, sent|defwinproc|optional },
3807     { 0 }
3808 };
3809
3810 static const struct message WmGetUpdateRect[] = {
3811     { WM_NCPAINT, sent },
3812     { WM_GETTEXT, sent|defwinproc|optional },
3813     { WM_PAINT, sent },
3814     { 0 }
3815 };
3816
3817 static const struct message WmInvalidateFull[] = {
3818     { WM_NCPAINT, sent|wparam, 1 },
3819     { WM_GETTEXT, sent|defwinproc|optional },
3820     { 0 }
3821 };
3822
3823 static const struct message WmInvalidateErase[] = {
3824     { WM_NCPAINT, sent|wparam, 1 },
3825     { WM_GETTEXT, sent|defwinproc|optional },
3826     { WM_ERASEBKGND, sent },
3827     { 0 }
3828 };
3829
3830 static const struct message WmInvalidatePaint[] = {
3831     { WM_PAINT, sent },
3832     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
3833     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3834     { 0 }
3835 };
3836
3837 static const struct message WmInvalidateErasePaint[] = {
3838     { WM_PAINT, sent },
3839     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
3840     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3841     { WM_ERASEBKGND, sent|beginpaint },
3842     { 0 }
3843 };
3844
3845 static const struct message WmInvalidateErasePaint2[] = {
3846     { WM_PAINT, sent },
3847     { WM_NCPAINT, sent|beginpaint },
3848     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3849     { WM_ERASEBKGND, sent|beginpaint },
3850     { 0 }
3851 };
3852
3853 static const struct message WmErase[] = {
3854     { WM_ERASEBKGND, sent },
3855     { 0 }
3856 };
3857
3858 static const struct message WmPaint[] = {
3859     { WM_PAINT, sent },
3860     { 0 }
3861 };
3862
3863 static const struct message WmParentOnlyPaint[] = {
3864     { WM_PAINT, sent|parent },
3865     { 0 }
3866 };
3867
3868 static const struct message WmInvalidateParent[] = {
3869     { WM_NCPAINT, sent|parent },
3870     { WM_GETTEXT, sent|defwinproc|parent|optional },
3871     { WM_ERASEBKGND, sent|parent },
3872     { 0 }
3873 };
3874
3875 static const struct message WmInvalidateParentChild[] = {
3876     { WM_NCPAINT, sent|parent },
3877     { WM_GETTEXT, sent|defwinproc|parent|optional },
3878     { WM_ERASEBKGND, sent|parent },
3879     { WM_NCPAINT, sent },
3880     { WM_GETTEXT, sent|defwinproc|optional },
3881     { WM_ERASEBKGND, sent },
3882     { 0 }
3883 };
3884
3885 static const struct message WmInvalidateParentChild2[] = {
3886     { WM_ERASEBKGND, sent|parent },
3887     { WM_NCPAINT, sent },
3888     { WM_GETTEXT, sent|defwinproc|optional },
3889     { WM_ERASEBKGND, sent },
3890     { 0 }
3891 };
3892
3893 static const struct message WmParentPaint[] = {
3894     { WM_PAINT, sent|parent },
3895     { WM_PAINT, sent },
3896     { 0 }
3897 };
3898
3899 static const struct message WmParentPaintNc[] = {
3900     { WM_PAINT, sent|parent },
3901     { WM_PAINT, sent },
3902     { WM_NCPAINT, sent|beginpaint },
3903     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3904     { WM_ERASEBKGND, sent|beginpaint },
3905     { 0 }
3906 };
3907
3908 static const struct message WmChildPaintNc[] = {
3909     { WM_PAINT, sent },
3910     { WM_NCPAINT, sent|beginpaint },
3911     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3912     { WM_ERASEBKGND, sent|beginpaint },
3913     { 0 }
3914 };
3915
3916 static const struct message WmParentErasePaint[] = {
3917     { WM_PAINT, sent|parent },
3918     { WM_NCPAINT, sent|parent|beginpaint },
3919     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
3920     { WM_ERASEBKGND, sent|parent|beginpaint },
3921     { WM_PAINT, sent },
3922     { WM_NCPAINT, sent|beginpaint },
3923     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
3924     { WM_ERASEBKGND, sent|beginpaint },
3925     { 0 }
3926 };
3927
3928 static const struct message WmParentOnlyNcPaint[] = {
3929     { WM_PAINT, sent|parent },
3930     { WM_NCPAINT, sent|parent|beginpaint },
3931     { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
3932     { 0 }
3933 };
3934
3935 static const struct message WmSetParentStyle[] = {
3936     { WM_STYLECHANGING, sent|parent },
3937     { WM_STYLECHANGED, sent|parent },
3938     { 0 }
3939 };
3940
3941 static void test_paint_messages(void)
3942 {
3943     BOOL ret;
3944     RECT rect;
3945     POINT pt;
3946     MSG msg;
3947     HWND hparent, hchild;
3948     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
3949     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
3950     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
3951                                 100, 100, 200, 200, 0, 0, 0, NULL);
3952     ok (hwnd != 0, "Failed to create overlapped window\n");
3953
3954     ShowWindow( hwnd, SW_SHOW );
3955     UpdateWindow( hwnd );
3956     flush_events();
3957
3958     check_update_rgn( hwnd, 0 );
3959     SetRectRgn( hrgn, 10, 10, 20, 20 );
3960     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3961     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
3962     check_update_rgn( hwnd, hrgn );
3963     SetRectRgn( hrgn2, 20, 20, 30, 30 );
3964     ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
3965     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
3966     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
3967     check_update_rgn( hwnd, hrgn );
3968     /* validate everything */
3969     ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
3970     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
3971     check_update_rgn( hwnd, 0 );
3972
3973     /* test empty region */
3974     SetRectRgn( hrgn, 10, 10, 10, 15 );
3975     ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
3976     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
3977     check_update_rgn( hwnd, 0 );
3978     /* test empty rect */
3979     SetRect( &rect, 10, 10, 10, 15 );
3980     ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
3981     ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
3982     check_update_rgn( hwnd, 0 );
3983
3984     /* flush pending messages */
3985     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3986     flush_sequence();
3987
3988     GetClientRect( hwnd, &rect );
3989     SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
3990     /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
3991      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
3992      */
3993     trace("testing InvalidateRect(0, NULL, FALSE)\n");
3994     SetRectEmpty( &rect );
3995     ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
3996     check_update_rgn( hwnd, hrgn );
3997     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
3998     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
3999     ok_sequence( WmPaint, "Paint", FALSE );
4000     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4001     check_update_rgn( hwnd, 0 );
4002
4003     /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
4004      * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
4005      */
4006     trace("testing ValidateRect(0, NULL)\n");
4007     SetRectEmpty( &rect );
4008     ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n");
4009     check_update_rgn( hwnd, hrgn );
4010     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4011     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4012     ok_sequence( WmPaint, "Paint", FALSE );
4013     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
4014     check_update_rgn( hwnd, 0 );
4015
4016     trace("testing InvalidateRgn(0, NULL, FALSE)\n");
4017     SetLastError(0xdeadbeef);
4018     ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
4019     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %ld\n", GetLastError());
4020     check_update_rgn( hwnd, 0 );
4021     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4022     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
4023
4024     trace("testing ValidateRgn(0, NULL)\n");
4025     SetLastError(0xdeadbeef);
4026     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
4027     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %ld\n", GetLastError());
4028     check_update_rgn( hwnd, 0 );
4029     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4030     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
4031
4032     /* now with frame */
4033     SetRectRgn( hrgn, -5, -5, 20, 20 );
4034
4035     /* flush pending messages */
4036     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4037
4038     flush_sequence();
4039     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4040     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
4041
4042     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
4043     check_update_rgn( hwnd, hrgn );
4044
4045     flush_sequence();
4046     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
4047     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
4048
4049     flush_sequence();
4050     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
4051     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
4052
4053     GetClientRect( hwnd, &rect );
4054     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
4055     check_update_rgn( hwnd, hrgn );
4056
4057     flush_sequence();
4058     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
4059     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
4060
4061     flush_sequence();
4062     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
4063     ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
4064     check_update_rgn( hwnd, 0 );
4065
4066     flush_sequence();
4067     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
4068     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
4069     check_update_rgn( hwnd, 0 );
4070
4071     flush_sequence();
4072     SetRectRgn( hrgn, 0, 0, 100, 100 );
4073     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
4074     SetRectRgn( hrgn, 0, 0, 50, 100 );
4075     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
4076     SetRectRgn( hrgn, 50, 0, 100, 100 );
4077     check_update_rgn( hwnd, hrgn );
4078     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
4079     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
4080     check_update_rgn( hwnd, 0 );
4081
4082     flush_sequence();
4083     SetRectRgn( hrgn, 0, 0, 100, 100 );
4084     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
4085     SetRectRgn( hrgn, 0, 0, 100, 50 );
4086     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
4087     ok_sequence( WmErase, "Erase", FALSE );
4088     SetRectRgn( hrgn, 0, 50, 100, 100 );
4089     check_update_rgn( hwnd, hrgn );
4090
4091     flush_sequence();
4092     SetRectRgn( hrgn, 0, 0, 100, 100 );
4093     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
4094     SetRectRgn( hrgn, 0, 0, 50, 50 );
4095     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
4096     ok_sequence( WmPaint, "Paint", FALSE );
4097
4098     flush_sequence();
4099     SetRectRgn( hrgn, -4, -4, -2, -2 );
4100     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4101     SetRectRgn( hrgn, -200, -200, -198, -198 );
4102     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
4103     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
4104
4105     flush_sequence();
4106     SetRectRgn( hrgn, -4, -4, -2, -2 );
4107     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4108     SetRectRgn( hrgn, -4, -4, -3, -3 );
4109     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
4110     SetRectRgn( hrgn, 0, 0, 1, 1 );
4111     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
4112     ok_sequence( WmPaint, "Paint", FALSE );
4113
4114     flush_sequence();
4115     SetRectRgn( hrgn, -4, -4, -1, -1 );
4116     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4117     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
4118     /* make sure no WM_PAINT was generated */
4119     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4120     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
4121
4122     flush_sequence();
4123     SetRectRgn( hrgn, -4, -4, -1, -1 );
4124     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
4125     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
4126     {
4127         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
4128         {
4129             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
4130             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
4131             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
4132             ret = GetUpdateRect( hwnd, &rect, FALSE );
4133             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
4134             /* this will send WM_NCPAINT and validate the non client area */
4135             ret = GetUpdateRect( hwnd, &rect, TRUE );
4136             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
4137         }
4138         DispatchMessage( &msg );
4139     }
4140     ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
4141
4142     DestroyWindow( hwnd );
4143
4144     /* now test with a child window */
4145
4146     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
4147                               100, 100, 200, 200, 0, 0, 0, NULL);
4148     ok (hparent != 0, "Failed to create parent window\n");
4149
4150     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
4151                            10, 10, 100, 100, hparent, 0, 0, NULL);
4152     ok (hchild != 0, "Failed to create child window\n");
4153
4154     ShowWindow( hparent, SW_SHOW );
4155     UpdateWindow( hparent );
4156     UpdateWindow( hchild );
4157     flush_events();
4158     flush_sequence();
4159     log_all_parent_messages++;
4160
4161     SetRect( &rect, 0, 0, 50, 50 );
4162     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4163     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
4164     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
4165
4166     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4167     pt.x = pt.y = 0;
4168     MapWindowPoints( hchild, hparent, &pt, 1 );
4169     SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
4170     check_update_rgn( hchild, hrgn );
4171     SetRectRgn( hrgn, 0, 0, 50, 50 );
4172     check_update_rgn( hparent, hrgn );
4173     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4174     ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
4175     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
4176     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
4177
4178     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4179     ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
4180
4181     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
4182     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4183     ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
4184     RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
4185     ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
4186
4187     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
4188     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
4189     ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
4190
4191     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
4192     flush_sequence();
4193     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
4194     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4195     ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
4196
4197     /* flush all paint messages */
4198     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4199     flush_sequence();
4200
4201     /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
4202     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
4203     SetRectRgn( hrgn, 0, 0, 50, 50 );
4204     check_update_rgn( hparent, hrgn );
4205     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
4206     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
4207     SetRectRgn( hrgn, 0, 0, 50, 50 );
4208     check_update_rgn( hparent, hrgn );
4209
4210     /* flush all paint messages */
4211     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4212     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
4213     flush_sequence();
4214
4215     /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
4216     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4217     SetRectRgn( hrgn, 0, 0, 50, 50 );
4218     check_update_rgn( hparent, hrgn );
4219     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
4220     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
4221     SetRectRgn( hrgn2, 10, 10, 50, 50 );
4222     CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
4223     check_update_rgn( hparent, hrgn );
4224     /* flush all paint messages */
4225     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4226     flush_sequence();
4227
4228     /* same as above but parent gets completely validated */
4229     SetRect( &rect, 20, 20, 30, 30 );
4230     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4231     SetRectRgn( hrgn, 20, 20, 30, 30 );
4232     check_update_rgn( hparent, hrgn );
4233     RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
4234     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
4235     check_update_rgn( hparent, 0 );  /* no update region */
4236     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4237     ok_sequence( WmEmptySeq, "WmEmpty", FALSE );  /* and no paint messages */
4238
4239     /* make sure RDW_VALIDATE on child doesn't have the same effect */
4240     flush_sequence();
4241     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4242     SetRectRgn( hrgn, 20, 20, 30, 30 );
4243     check_update_rgn( hparent, hrgn );
4244     RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
4245     SetRectRgn( hrgn, 20, 20, 30, 30 );
4246     check_update_rgn( hparent, hrgn );
4247
4248     /* same as above but normal WM_PAINT doesn't validate parent */
4249     flush_sequence();
4250     SetRect( &rect, 20, 20, 30, 30 );
4251     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4252     SetRectRgn( hrgn, 20, 20, 30, 30 );
4253     check_update_rgn( hparent, hrgn );
4254     /* no WM_PAINT in child while parent still pending */
4255     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4256     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
4257     while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4258     ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
4259
4260     flush_sequence();
4261     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4262     /* no WM_PAINT in child while parent still pending */
4263     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4264     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
4265     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
4266     /* now that parent is valid child should get WM_PAINT */
4267     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4268     ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
4269     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4270     ok_sequence( WmEmptySeq, "No other message", FALSE );
4271
4272     /* same thing with WS_CLIPCHILDREN in parent */
4273     flush_sequence();
4274     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
4275     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
4276     /* changing style invalidates non client area, but we need to invalidate something else to see it */
4277     RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
4278     ok_sequence( WmEmptySeq, "No message", FALSE );
4279     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
4280     ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
4281
4282     flush_sequence();
4283     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
4284     SetRectRgn( hrgn, 20, 20, 30, 30 );
4285     check_update_rgn( hparent, hrgn );
4286     /* no WM_PAINT in child while parent still pending */
4287     while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4288     ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
4289     /* WM_PAINT in parent first */
4290     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4291     ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
4292
4293     /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
4294     flush_sequence();
4295     SetRect( &rect, 0, 0, 30, 30 );
4296     RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
4297     SetRectRgn( hrgn, 0, 0, 30, 30 );
4298     check_update_rgn( hparent, hrgn );
4299     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4300     ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
4301
4302     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
4303     flush_sequence();
4304     SetRect( &rect, -10, 0, 30, 30 );
4305     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
4306     SetRect( &rect, 0, 0, 20, 20 );
4307     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
4308     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
4309     ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
4310
4311     /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
4312     flush_sequence();
4313     SetRect( &rect, -10, 0, 30, 30 );
4314     RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
4315     SetRect( &rect, 0, 0, 100, 100 );
4316     RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
4317     RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
4318     ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
4319     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
4320     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
4321
4322     /* test RDW_INTERNALPAINT behavior */
4323
4324     flush_sequence();
4325     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
4326     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4327     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
4328
4329     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
4330     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4331     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
4332
4333     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
4334     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4335     ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
4336
4337     assert( GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
4338     UpdateWindow( hparent );
4339     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4340     flush_sequence();
4341     trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
4342     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4343     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4344                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4345     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4346     ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
4347
4348     UpdateWindow( hparent );
4349     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4350     flush_sequence();
4351     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
4352     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4353     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
4354                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4355     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4356     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
4357
4358     SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
4359     ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
4360     RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
4361     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4362     ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
4363
4364     assert( !(GetWindowLong(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
4365     UpdateWindow( hparent );
4366     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4367     flush_sequence();
4368     trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
4369     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4370     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4371                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4372     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4373     ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
4374
4375     UpdateWindow( hparent );
4376     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4377     flush_sequence();
4378     trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
4379     RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
4380     SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
4381                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
4382     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
4383     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
4384
4385     log_all_parent_messages--;
4386     DestroyWindow( hparent );
4387     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
4388
4389     DeleteObject( hrgn );
4390     DeleteObject( hrgn2 );
4391 }
4392
4393 struct wnd_event
4394 {
4395     HWND hwnd;
4396     HANDLE event;
4397 };
4398
4399 static DWORD WINAPI thread_proc(void *param)
4400 {
4401     MSG msg;
4402     struct wnd_event *wnd_event = (struct wnd_event *)param;
4403
4404     wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
4405                                       100, 100, 200, 200, 0, 0, 0, NULL);
4406     ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
4407
4408     SetEvent(wnd_event->event);
4409
4410     while (GetMessage(&msg, 0, 0, 0))
4411     {
4412         TranslateMessage(&msg);
4413         DispatchMessage(&msg);
4414     }
4415
4416     ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
4417
4418     return 0;
4419 }
4420
4421 static void test_interthread_messages(void)
4422 {
4423     HANDLE hThread;
4424     DWORD tid;
4425     WNDPROC proc;
4426     MSG msg;
4427     char buf[256];
4428     int len, expected_len;
4429     struct wnd_event wnd_event;
4430     BOOL ret;
4431
4432     wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
4433     if (!wnd_event.event)
4434     {
4435         trace("skipping interthread message test under win9x\n");
4436         return;
4437     }
4438
4439     hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
4440     ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
4441
4442     ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
4443
4444     CloseHandle(wnd_event.event);
4445
4446     SetLastError(0xdeadbeef);
4447     ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
4448     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
4449
4450     proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
4451     ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
4452
4453     expected_len = lstrlenA("window caption text");
4454     memset(buf, 0, sizeof(buf));
4455     SetLastError(0xdeadbeef);
4456     len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
4457     ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
4458     ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
4459
4460     msg.hwnd = wnd_event.hwnd;
4461     msg.message = WM_GETTEXT;
4462     msg.wParam = sizeof(buf);
4463     msg.lParam = (LPARAM)buf;
4464     memset(buf, 0, sizeof(buf));
4465     SetLastError(0xdeadbeef);
4466     len = DispatchMessageA(&msg);
4467     ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
4468        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
4469
4470     /* the following test causes an exception in user.exe under win9x */
4471     msg.hwnd = wnd_event.hwnd;
4472     msg.message = WM_TIMER;
4473     msg.wParam = 0;
4474     msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
4475     SetLastError(0xdeadbeef);
4476     len = DispatchMessageA(&msg);
4477     ok(!len && GetLastError() == 0xdeadbeef,
4478        "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
4479
4480     ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
4481     ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
4482
4483     ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
4484     CloseHandle(hThread);
4485
4486     ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
4487 }
4488
4489
4490 static const struct message WmVkN[] = {
4491     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
4492     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
4493     { WM_CHAR, wparam|lparam, 'n', 1 },
4494     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
4495     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
4496     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
4497     { 0 }
4498 };
4499 static const struct message WmShiftVkN[] = {
4500     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
4501     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
4502     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
4503     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
4504     { WM_CHAR, wparam|lparam, 'N', 1 },
4505     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
4506     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
4507     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
4508     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
4509     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
4510     { 0 }
4511 };
4512 static const struct message WmCtrlVkN[] = {
4513     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
4514     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
4515     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
4516     { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
4517     { WM_CHAR, wparam|lparam, 0x000e, 1 },
4518     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
4519     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
4520     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
4521     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
4522     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
4523     { 0 }
4524 };
4525 static const struct message WmCtrlVkN_2[] = {
4526     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
4527     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
4528     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
4529     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
4530     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
4531     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
4532     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
4533     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
4534     { 0 }
4535 };
4536 static const struct message WmAltVkN[] = {
4537     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4538     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4539     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
4540     { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
4541     { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
4542     { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
4543     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
4544     { HCBT_SYSCOMMAND, hook },
4545     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
4546     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4547     { 0x00AE, sent|defwinproc|optional }, /* XP */
4548     { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
4549     { WM_INITMENU, sent|defwinproc },
4550     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4551     { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
4552     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
4553     { WM_CAPTURECHANGED, sent|defwinproc },
4554     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
4555     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4556     { WM_EXITMENULOOP, sent|defwinproc },
4557     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
4558     { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
4559     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
4560     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4561     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4562     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4563     { 0 }
4564 };
4565 static const struct message WmAltVkN_2[] = {
4566     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4567     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4568     { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
4569     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
4570     { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
4571     { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4572     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4573     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4574     { 0 }
4575 };
4576 static const struct message WmCtrlAltVkN[] = {
4577     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
4578     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
4579     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4580     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4581     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
4582     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
4583     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
4584     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4585     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4586     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4587     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
4588     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
4589     { 0 }
4590 };
4591 static const struct message WmCtrlShiftVkN[] = {
4592     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
4593     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
4594     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
4595     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
4596     { WM_KEYDOWN, wparam|lparam, 'N', 1 },
4597     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
4598     { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
4599     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
4600     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
4601     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
4602     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
4603     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
4604     { 0 }
4605 };
4606 static const struct message WmCtrlAltShiftVkN[] = {
4607     { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
4608     { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
4609     { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4610     { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4611     { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
4612     { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
4613     { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
4614     { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
4615     { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
4616     { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
4617     { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
4618     { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
4619     { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4620     { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4621     { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
4622     { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
4623     { 0 }
4624 };
4625 static const struct message WmAltPressRelease[] = {
4626     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4627     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4628     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4629     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4630     { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
4631     { HCBT_SYSCOMMAND, hook },
4632     { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
4633     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
4634     { WM_INITMENU, sent|defwinproc },
4635     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4636     { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
4637     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
4638
4639     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4640     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
4641     { WM_CAPTURECHANGED, sent|defwinproc },
4642     { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
4643     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
4644     { WM_EXITMENULOOP, sent|defwinproc },
4645     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4646     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4647     { 0 }
4648 };
4649 static const struct message WmAltMouseButton[] = {
4650     { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
4651     { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
4652     { WM_MOUSEMOVE, wparam|optional, 0, 0 },
4653     { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
4654     { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
4655     { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
4656     { WM_LBUTTONUP, wparam, 0, 0 },
4657     { WM_LBUTTONUP, sent|wparam, 0, 0 },
4658     { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
4659     { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
4660     { 0 }
4661 };
4662 static const struct message WmF1Seq[] = {
4663     { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
4664     { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
4665     { 0x4d, wparam|lparam, 0, 0 },
4666     { 0x4d, sent|wparam|lparam, 0, 0 },
4667     { WM_HELP, sent|defwinproc },
4668     { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
4669     { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
4670     { 0 }
4671 };
4672
4673 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
4674 {
4675     MSG msg;
4676
4677     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
4678     {
4679         struct message log_msg;
4680
4681         trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
4682
4683         /* ignore some unwanted messages */
4684         if (msg.message == WM_MOUSEMOVE ||
4685             msg.message == WM_GETICON ||
4686             msg.message == WM_DEVICECHANGE)
4687             continue;
4688
4689         log_msg.message = msg.message;
4690         log_msg.flags = wparam|lparam;
4691         log_msg.wParam = msg.wParam;
4692         log_msg.lParam = msg.lParam;
4693         add_message(&log_msg);
4694
4695         if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
4696         {
4697             TranslateMessage(&msg);
4698             DispatchMessage(&msg);
4699         }
4700     }
4701 }
4702
4703 static void test_accelerators(void)
4704 {
4705     RECT rc;
4706     SHORT state;
4707     HACCEL hAccel;
4708     HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4709                                 100, 100, 200, 200, 0, 0, 0, NULL);
4710     BOOL ret;
4711
4712     assert(hwnd != 0);
4713     UpdateWindow(hwnd);
4714     flush_events();
4715     SetFocus(hwnd);
4716     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
4717
4718     state = GetKeyState(VK_SHIFT);
4719     ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
4720     state = GetKeyState(VK_CAPITAL);
4721     ok(state == 0, "wrong CapsLock state %04x\n", state);
4722
4723     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
4724     assert(hAccel != 0);
4725
4726     pump_msg_loop(hwnd, 0);
4727     flush_sequence();
4728
4729     trace("testing VK_N press/release\n");
4730     flush_sequence();
4731     keybd_event('N', 0, 0, 0);
4732     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4733     pump_msg_loop(hwnd, hAccel);
4734     ok_sequence(WmVkN, "VK_N press/release", FALSE);
4735
4736     trace("testing Shift+VK_N press/release\n");
4737     flush_sequence();
4738     keybd_event(VK_SHIFT, 0, 0, 0);
4739     keybd_event('N', 0, 0, 0);
4740     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4741     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4742     pump_msg_loop(hwnd, hAccel);
4743     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
4744
4745     trace("testing Ctrl+VK_N press/release\n");
4746     flush_sequence();
4747     keybd_event(VK_CONTROL, 0, 0, 0);
4748     keybd_event('N', 0, 0, 0);
4749     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4750     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4751     pump_msg_loop(hwnd, hAccel);
4752     ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
4753
4754     trace("testing Alt+VK_N press/release\n");
4755     flush_sequence();
4756     keybd_event(VK_MENU, 0, 0, 0);
4757     keybd_event('N', 0, 0, 0);
4758     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4759     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4760     pump_msg_loop(hwnd, hAccel);
4761     ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
4762
4763     trace("testing Ctrl+Alt+VK_N press/release 1\n");
4764     flush_sequence();
4765     keybd_event(VK_CONTROL, 0, 0, 0);
4766     keybd_event(VK_MENU, 0, 0, 0);
4767     keybd_event('N', 0, 0, 0);
4768     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4769     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4770     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4771     pump_msg_loop(hwnd, hAccel);
4772     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
4773
4774     ret = DestroyAcceleratorTable(hAccel);
4775     ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
4776
4777     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
4778     assert(hAccel != 0);
4779
4780     trace("testing VK_N press/release\n");
4781     flush_sequence();
4782     keybd_event('N', 0, 0, 0);
4783     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4784     pump_msg_loop(hwnd, hAccel);
4785     ok_sequence(WmVkN, "VK_N press/release", FALSE);
4786
4787     trace("testing Shift+VK_N press/release\n");
4788     flush_sequence();
4789     keybd_event(VK_SHIFT, 0, 0, 0);
4790     keybd_event('N', 0, 0, 0);
4791     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4792     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4793     pump_msg_loop(hwnd, hAccel);
4794     ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
4795
4796     trace("testing Ctrl+VK_N press/release 2\n");
4797     flush_sequence();
4798     keybd_event(VK_CONTROL, 0, 0, 0);
4799     keybd_event('N', 0, 0, 0);
4800     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4801     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4802     pump_msg_loop(hwnd, hAccel);
4803     ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
4804
4805     trace("testing Alt+VK_N press/release 2\n");
4806     flush_sequence();
4807     keybd_event(VK_MENU, 0, 0, 0);
4808     keybd_event('N', 0, 0, 0);
4809     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4810     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4811     pump_msg_loop(hwnd, hAccel);
4812     ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
4813
4814     trace("testing Ctrl+Alt+VK_N press/release 2\n");
4815     flush_sequence();
4816     keybd_event(VK_CONTROL, 0, 0, 0);
4817     keybd_event(VK_MENU, 0, 0, 0);
4818     keybd_event('N', 0, 0, 0);
4819     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4820     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4821     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4822     pump_msg_loop(hwnd, hAccel);
4823     ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
4824
4825     trace("testing Ctrl+Shift+VK_N press/release\n");
4826     flush_sequence();
4827     keybd_event(VK_CONTROL, 0, 0, 0);
4828     keybd_event(VK_SHIFT, 0, 0, 0);
4829     keybd_event('N', 0, 0, 0);
4830     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4831     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4832     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4833     pump_msg_loop(hwnd, hAccel);
4834     ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
4835
4836     trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
4837     flush_sequence();
4838     keybd_event(VK_CONTROL, 0, 0, 0);
4839     keybd_event(VK_MENU, 0, 0, 0);
4840     keybd_event(VK_SHIFT, 0, 0, 0);
4841     keybd_event('N', 0, 0, 0);
4842     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
4843     keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
4844     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4845     keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
4846     pump_msg_loop(hwnd, hAccel);
4847     ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
4848
4849     ret = DestroyAcceleratorTable(hAccel);
4850     ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
4851
4852     trace("testing Alt press/release\n");
4853     flush_sequence();
4854     keybd_event(VK_MENU, 0, 0, 0);
4855     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4856     keybd_event(VK_MENU, 0, 0, 0);
4857     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4858     pump_msg_loop(hwnd, 0);
4859     /* this test doesn't pass in Wine for managed windows */
4860     ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
4861
4862     trace("testing Alt+MouseButton press/release\n");
4863     /* first, move mouse pointer inside of the window client area */
4864     GetClientRect(hwnd, &rc);
4865     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
4866     rc.left += (rc.right - rc.left)/2;
4867     rc.top += (rc.bottom - rc.top)/2;
4868     SetCursorPos(rc.left, rc.top);
4869
4870     pump_msg_loop(hwnd, 0);
4871     flush_sequence();
4872     keybd_event(VK_MENU, 0, 0, 0);
4873     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
4874     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
4875     keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
4876     pump_msg_loop(hwnd, 0);
4877     ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
4878
4879     keybd_event(VK_F1, 0, 0, 0);
4880     keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
4881     pump_msg_loop(hwnd, 0);
4882     ok_sequence(WmF1Seq, "F1 press/release", TRUE);
4883
4884     DestroyWindow(hwnd);
4885 }
4886
4887 /************* window procedures ********************/
4888
4889 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, 
4890                              WPARAM wParam, LPARAM lParam)
4891 {
4892     static long defwndproc_counter = 0;
4893     static long beginpaint_counter = 0;
4894     LRESULT ret;
4895     struct message msg;
4896
4897     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
4898
4899     /* explicitly ignore WM_GETICON message */
4900     if (message == WM_GETICON) return 0;
4901
4902     switch (message)
4903     {
4904         case WM_ENABLE:
4905         {
4906             LONG style = GetWindowLongA(hwnd, GWL_STYLE);
4907             ok((BOOL)wParam == !(style & WS_DISABLED),
4908                 "wrong WS_DISABLED state: %d != %d\n", wParam, !(style & WS_DISABLED));
4909             break;
4910         }
4911
4912         case WM_CAPTURECHANGED:
4913             if (test_DestroyWindow_flag)
4914             {
4915                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4916                 if (style & WS_CHILD)
4917                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
4918                 else if (style & WS_POPUP)
4919                     lParam = WND_POPUP_ID;
4920                 else
4921                     lParam = WND_PARENT_ID;
4922             }
4923             break;
4924
4925         case WM_NCDESTROY:
4926         {
4927             HWND capture;
4928
4929             ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
4930             capture = GetCapture();
4931             if (capture)
4932             {
4933                 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
4934                 trace("current capture %p, releasing...\n", capture);
4935                 ReleaseCapture();
4936             }
4937         }
4938         /* fall through */
4939         case WM_DESTROY:
4940             if (pGetAncestor)
4941                 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
4942             if (test_DestroyWindow_flag)
4943             {
4944                 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4945                 if (style & WS_CHILD)
4946                     lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
4947                 else if (style & WS_POPUP)
4948                     lParam = WND_POPUP_ID;
4949                 else
4950                     lParam = WND_PARENT_ID;
4951             }
4952             break;
4953
4954         /* test_accelerators() depends on this */
4955         case WM_NCHITTEST:
4956             return HTCLIENT;
4957     
4958         /* ignore */
4959         case WM_MOUSEMOVE:
4960         case WM_SETCURSOR:
4961         case WM_DEVICECHANGE:
4962             return 0;
4963
4964         case WM_WINDOWPOSCHANGING:
4965         case WM_WINDOWPOSCHANGED:
4966         {
4967             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
4968
4969             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
4970             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
4971                   winpos->hwnd, winpos->hwndInsertAfter,
4972                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
4973
4974             /* Log only documented flags, win2k uses 0x1000 and 0x2000
4975              * in the high word for internal purposes
4976              */
4977             wParam = winpos->flags & 0xffff;
4978             break;
4979         }
4980     }
4981
4982     msg.message = message;
4983     msg.flags = sent|wparam|lparam;
4984     if (defwndproc_counter) msg.flags |= defwinproc;
4985     if (beginpaint_counter) msg.flags |= beginpaint;
4986     msg.wParam = wParam;
4987     msg.lParam = lParam;
4988     add_message(&msg);
4989
4990     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
4991     {
4992         HWND parent = GetParent(hwnd);
4993         RECT rc;
4994         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
4995
4996         GetClientRect(parent, &rc);
4997         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
4998
4999         trace("ptReserved = (%ld,%ld)\n"
5000               "ptMaxSize = (%ld,%ld)\n"
5001               "ptMaxPosition = (%ld,%ld)\n"
5002               "ptMinTrackSize = (%ld,%ld)\n"
5003               "ptMaxTrackSize = (%ld,%ld)\n",
5004               minmax->ptReserved.x, minmax->ptReserved.y,
5005               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
5006               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
5007               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
5008               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
5009
5010         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
5011            minmax->ptMaxSize.x, rc.right);
5012         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
5013            minmax->ptMaxSize.y, rc.bottom);
5014     }
5015
5016     if (message == WM_PAINT)
5017     {
5018         PAINTSTRUCT ps;
5019         beginpaint_counter++;
5020         BeginPaint( hwnd, &ps );
5021         beginpaint_counter--;
5022         EndPaint( hwnd, &ps );
5023         return 0;
5024     }
5025
5026     defwndproc_counter++;
5027     ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) 
5028                   : DefWindowProcA(hwnd, message, wParam, lParam);
5029     defwndproc_counter--;
5030
5031     return ret;
5032 }
5033
5034 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5035 {
5036     return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
5037 }
5038
5039 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5040 {
5041     return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
5042 }
5043
5044 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5045 {
5046     static long defwndproc_counter = 0;
5047     LRESULT ret;
5048     struct message msg;
5049
5050     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
5051
5052     /* explicitly ignore WM_GETICON message */
5053     if (message == WM_GETICON) return 0;
5054
5055     msg.message = message;
5056     msg.flags = sent|wparam|lparam;
5057     if (defwndproc_counter) msg.flags |= defwinproc;
5058     msg.wParam = wParam;
5059     msg.lParam = lParam;
5060     add_message(&msg);
5061
5062     if (message == WM_CREATE)
5063     {
5064         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
5065         SetWindowLongA(hwnd, GWL_STYLE, style);
5066     }
5067
5068     defwndproc_counter++;
5069     ret = DefWindowProcA(hwnd, message, wParam, lParam);
5070     defwndproc_counter--;
5071
5072     return ret;
5073 }
5074
5075 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5076 {
5077     static long defwndproc_counter = 0;
5078     static long beginpaint_counter = 0;
5079     LRESULT ret;
5080     struct message msg;
5081
5082     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
5083
5084     /* explicitly ignore WM_GETICON message */
5085     if (message == WM_GETICON) return 0;
5086
5087     if (log_all_parent_messages ||
5088         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
5089         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
5090         message == WM_ENABLE || message == WM_ENTERIDLE ||
5091         message == WM_IME_SETCONTEXT)
5092     {
5093         switch (message)
5094         {
5095             case WM_ERASEBKGND:
5096             {
5097                 RECT rc;
5098                 INT ret = GetClipBox((HDC)wParam, &rc);
5099
5100                 trace("WM_ERASEBKGND: GetClipBox()=%d, (%ld,%ld-%ld,%ld)\n",
5101                        ret, rc.left, rc.top, rc.right, rc.bottom);
5102                 break;
5103             }
5104
5105             case WM_WINDOWPOSCHANGING:
5106             case WM_WINDOWPOSCHANGED:
5107             {
5108                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
5109
5110                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
5111                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
5112                       winpos->hwnd, winpos->hwndInsertAfter,
5113                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
5114
5115                 /* Log only documented flags, win2k uses 0x1000 and 0x2000
5116                  * in the high word for internal purposes
5117                  */
5118                 wParam = winpos->flags & 0xffff;
5119                 break;
5120             }
5121         }
5122
5123         msg.message = message;
5124         msg.flags = sent|parent|wparam|lparam;
5125         if (defwndproc_counter) msg.flags |= defwinproc;
5126         if (beginpaint_counter) msg.flags |= beginpaint;
5127         msg.wParam = wParam;
5128         msg.lParam = lParam;
5129         add_message(&msg);
5130     }
5131
5132     if (message == WM_PAINT)
5133     {
5134         PAINTSTRUCT ps;
5135         beginpaint_counter++;
5136         BeginPaint( hwnd, &ps );
5137         beginpaint_counter--;
5138         EndPaint( hwnd, &ps );
5139         return 0;
5140     }
5141
5142     defwndproc_counter++;
5143     ret = DefWindowProcA(hwnd, message, wParam, lParam);
5144     defwndproc_counter--;
5145
5146     return ret;
5147 }
5148
5149 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
5150 {
5151     static long defwndproc_counter = 0;
5152     LRESULT ret;
5153     struct message msg;
5154
5155     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
5156
5157     /* explicitly ignore WM_GETICON message */
5158     if (message == WM_GETICON) return 0;
5159
5160     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
5161     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
5162     if (after_end_dialog)
5163         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
5164     else
5165         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
5166
5167     switch (message)
5168     {
5169         case WM_WINDOWPOSCHANGING:
5170         case WM_WINDOWPOSCHANGED:
5171         {
5172             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
5173
5174             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
5175             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
5176                   winpos->hwnd, winpos->hwndInsertAfter,
5177                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
5178
5179             /* Log only documented flags, win2k uses 0x1000 and 0x2000
5180              * in the high word for internal purposes
5181              */
5182             wParam = winpos->flags & 0xffff;
5183             break;
5184         }
5185     }
5186
5187     msg.message = message;
5188     msg.flags = sent|wparam|lparam;
5189     if (defwndproc_counter) msg.flags |= defwinproc;
5190     msg.wParam = wParam;
5191     msg.lParam = lParam;
5192     add_message(&msg);
5193
5194     defwndproc_counter++;
5195     ret = DefDlgProcA(hwnd, message, wParam, lParam);
5196     defwndproc_counter--;
5197
5198     return ret;
5199 }
5200
5201 static BOOL RegisterWindowClasses(void)
5202 {
5203     WNDCLASSA cls;
5204
5205     cls.style = 0;
5206     cls.lpfnWndProc = MsgCheckProcA;
5207     cls.cbClsExtra = 0;
5208     cls.cbWndExtra = 0;
5209     cls.hInstance = GetModuleHandleA(0);
5210     cls.hIcon = 0;
5211     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
5212     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
5213     cls.lpszMenuName = NULL;
5214     cls.lpszClassName = "TestWindowClass";
5215     if(!RegisterClassA(&cls)) return FALSE;
5216
5217     cls.lpfnWndProc = PopupMsgCheckProcA;
5218     cls.lpszClassName = "TestPopupClass";
5219     if(!RegisterClassA(&cls)) return FALSE;
5220
5221     cls.lpfnWndProc = ParentMsgCheckProcA;
5222     cls.lpszClassName = "TestParentClass";
5223     if(!RegisterClassA(&cls)) return FALSE;
5224
5225     cls.lpfnWndProc = DefWindowProcA;
5226     cls.lpszClassName = "SimpleWindowClass";
5227     if(!RegisterClassA(&cls)) return FALSE;
5228
5229     cls.style = CS_NOCLOSE;
5230     cls.lpszClassName = "NoCloseWindowClass";
5231     if(!RegisterClassA(&cls)) return FALSE;
5232
5233     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
5234     cls.style = 0;
5235     cls.hInstance = GetModuleHandleA(0);
5236     cls.hbrBackground = 0;
5237     cls.lpfnWndProc = TestDlgProcA;
5238     cls.lpszClassName = "TestDialogClass";
5239     if(!RegisterClassA(&cls)) return FALSE;
5240
5241     return TRUE;
5242 }
5243
5244 static HHOOK hCBT_hook;
5245 static DWORD cbt_hook_thread_id;
5246
5247 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
5248
5249     static const char *CBT_code_name[10] = {
5250         "HCBT_MOVESIZE",
5251         "HCBT_MINMAX",
5252         "HCBT_QS",
5253         "HCBT_CREATEWND",
5254         "HCBT_DESTROYWND",
5255         "HCBT_ACTIVATE",
5256         "HCBT_CLICKSKIPPED",
5257         "HCBT_KEYSKIPPED",
5258         "HCBT_SYSCOMMAND",
5259         "HCBT_SETFOCUS" };
5260     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
5261     HWND hwnd;
5262     char buf[256];
5263
5264     trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam);
5265
5266     ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
5267
5268     if (nCode == HCBT_SYSCOMMAND)
5269     {
5270         struct message msg;
5271
5272         msg.message = nCode;
5273         msg.flags = hook|wparam|lparam;
5274         msg.wParam = wParam;
5275         msg.lParam = lParam;
5276         add_message(&msg);
5277
5278         return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
5279     }
5280
5281     if (nCode == HCBT_DESTROYWND)
5282     {
5283         if (test_DestroyWindow_flag)
5284         {
5285             DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
5286             if (style & WS_CHILD)
5287                 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
5288             else if (style & WS_POPUP)
5289                 lParam = WND_POPUP_ID;
5290             else
5291                 lParam = WND_PARENT_ID;
5292         }
5293     }
5294
5295     /* Log also SetFocus(0) calls */
5296     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
5297
5298     if (GetClassNameA(hwnd, buf, sizeof(buf)))
5299     {
5300         if (!lstrcmpiA(buf, "TestWindowClass") ||
5301             !lstrcmpiA(buf, "TestParentClass") ||
5302             !lstrcmpiA(buf, "TestPopupClass") ||
5303             !lstrcmpiA(buf, "SimpleWindowClass") ||
5304             !lstrcmpiA(buf, "TestDialogClass") ||
5305             !lstrcmpiA(buf, "MDI_frame_class") ||
5306             !lstrcmpiA(buf, "MDI_client_class") ||
5307             !lstrcmpiA(buf, "MDI_child_class") ||
5308             !lstrcmpiA(buf, "my_button_class") ||
5309             !lstrcmpiA(buf, "my_edit_class") ||
5310             !lstrcmpiA(buf, "static") ||
5311             !lstrcmpiA(buf, "#32770"))
5312         {
5313             struct message msg;
5314
5315             msg.message = nCode;
5316             msg.flags = hook|wparam|lparam;
5317             msg.wParam = wParam;
5318             msg.lParam = lParam;
5319             add_message(&msg);
5320         }
5321     }
5322     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
5323 }
5324
5325 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
5326                                     DWORD event,
5327                                     HWND hwnd,
5328                                     LONG object_id,
5329                                     LONG child_id,
5330                                     DWORD thread_id,
5331                                     DWORD event_time)
5332 {
5333     char buf[256];
5334
5335     trace("WEH:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n",
5336            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
5337
5338     ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
5339
5340     /* ignore mouse cursor events */
5341     if (object_id == OBJID_CURSOR) return;
5342
5343     if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
5344     {
5345         if (!hwnd ||
5346             !lstrcmpiA(buf, "TestWindowClass") ||
5347             !lstrcmpiA(buf, "TestParentClass") ||
5348             !lstrcmpiA(buf, "TestPopupClass") ||
5349             !lstrcmpiA(buf, "SimpleWindowClass") ||
5350             !lstrcmpiA(buf, "TestDialogClass") ||
5351             !lstrcmpiA(buf, "MDI_frame_class") ||
5352             !lstrcmpiA(buf, "MDI_client_class") ||
5353             !lstrcmpiA(buf, "MDI_child_class") ||
5354             !lstrcmpiA(buf, "my_button_class") ||
5355             !lstrcmpiA(buf, "my_edit_class") ||
5356             !lstrcmpiA(buf, "static") ||
5357             !lstrcmpiA(buf, "#32770"))
5358         {
5359             struct message msg;
5360
5361             msg.message = event;
5362             msg.flags = winevent_hook|wparam|lparam;
5363             msg.wParam = object_id;
5364             msg.lParam = child_id;
5365             add_message(&msg);
5366         }
5367     }
5368 }
5369
5370 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
5371 static const WCHAR wszAnsi[] = {'U',0};
5372
5373 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5374 {
5375     switch (uMsg)
5376     {
5377     case CB_FINDSTRINGEXACT:
5378         trace("String: %p\n", (LPCWSTR)lParam);
5379         if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
5380             return 1;
5381         if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
5382             return 0;
5383         return -1;
5384     }
5385     return DefWindowProcW(hwnd, uMsg, wParam, lParam);
5386 }
5387
5388 static const struct message WmGetTextLengthAfromW[] = {
5389     { WM_GETTEXTLENGTH, sent },
5390     { WM_GETTEXT, sent },
5391     { 0 }
5392 };
5393
5394 static const WCHAR testWindowClassW[] = 
5395 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
5396
5397 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
5398
5399 /* dummy window proc for WM_GETTEXTLENGTH test */
5400 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
5401 {
5402     switch(msg)
5403     {
5404     case WM_GETTEXTLENGTH:
5405         return lstrlenW(dummy_window_text) + 37;  /* some random length */
5406     case WM_GETTEXT:
5407         lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
5408         return lstrlenW( (LPWSTR)lp );
5409     default:
5410         return DefWindowProcW( hwnd, msg, wp, lp );
5411     }
5412 }
5413
5414 static void test_message_conversion(void)
5415 {
5416     static const WCHAR wszMsgConversionClass[] =
5417         {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
5418     WNDCLASSW cls;
5419     LRESULT lRes;
5420     HWND hwnd;
5421     WNDPROC wndproc, newproc;
5422     BOOL ret;
5423
5424     cls.style = 0;
5425     cls.lpfnWndProc = MsgConversionProcW;
5426     cls.cbClsExtra = 0;
5427     cls.cbWndExtra = 0;
5428     cls.hInstance = GetModuleHandleW(NULL);
5429     cls.hIcon = NULL;
5430     cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
5431     cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
5432     cls.lpszMenuName = NULL;
5433     cls.lpszClassName = wszMsgConversionClass;
5434     /* this call will fail on Win9x, but that doesn't matter as this test is
5435      * meaningless on those platforms */
5436     if(!RegisterClassW(&cls)) return;
5437
5438     cls.style = 0;
5439     cls.lpfnWndProc = MsgCheckProcW;
5440     cls.cbClsExtra = 0;
5441     cls.cbWndExtra = 0;
5442     cls.hInstance = GetModuleHandleW(0);
5443     cls.hIcon = 0;
5444     cls.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
5445     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
5446     cls.lpszMenuName = NULL;
5447     cls.lpszClassName = testWindowClassW;
5448     if(!RegisterClassW(&cls)) return;
5449
5450     hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
5451                            100, 100, 200, 200, 0, 0, 0, NULL);
5452     ok(hwnd != NULL, "Window creation failed\n");
5453
5454     /* {W, A} -> A */
5455
5456     wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
5457     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5458     ok(lRes == 0, "String should have been converted\n");
5459     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5460     ok(lRes == 1, "String shouldn't have been converted\n");
5461
5462     /* {W, A} -> W */
5463
5464     wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
5465     lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5466     ok(lRes == 1, "String shouldn't have been converted\n");
5467     lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5468     ok(lRes == 1, "String shouldn't have been converted\n");
5469
5470     /* Synchronous messages */
5471
5472     lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5473     ok(lRes == 0, "String should have been converted\n");
5474     lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5475     ok(lRes == 1, "String shouldn't have been converted\n");
5476
5477     /* Asynchronous messages */
5478
5479     SetLastError(0);
5480     lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5481     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5482         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5483     SetLastError(0);
5484     lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5485     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5486         "PostMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5487     SetLastError(0);
5488     lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5489     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5490         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5491     SetLastError(0);
5492     lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5493     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5494         "PosThreadtMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5495     SetLastError(0);
5496     lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5497     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5498         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5499     SetLastError(0);
5500     lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
5501     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5502         "SendNotifyMessage on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5503     SetLastError(0);
5504     lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
5505     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5506         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5507     SetLastError(0);
5508     lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
5509     ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
5510         "SendMessageCallback on sync only message returned %ld, last error %ld\n", lRes, GetLastError());
5511
5512     /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
5513
5514     hwnd = CreateWindowW (testWindowClassW, wszUnicode,
5515                           WS_OVERLAPPEDWINDOW,
5516                           100, 100, 200, 200, 0, 0, 0, NULL);
5517     assert(hwnd);
5518     flush_sequence();
5519     lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
5520     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
5521     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
5522         "got bad length %ld\n", lRes );
5523
5524     flush_sequence();
5525     lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
5526                             hwnd, WM_GETTEXTLENGTH, 0, 0);
5527     ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
5528     ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
5529         "got bad length %ld\n", lRes );
5530
5531     wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
5532     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
5533     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
5534     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
5535                                      NULL, 0, NULL, NULL ),
5536         "got bad length %ld\n", lRes );
5537
5538     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
5539     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
5540     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
5541                                      NULL, 0, NULL, NULL ),
5542         "got bad length %ld\n", lRes );
5543
5544     ret = DestroyWindow(hwnd);
5545     ok( ret, "DestroyWindow() error %ld\n", GetLastError());
5546 }
5547
5548 struct timer_info
5549 {
5550     HWND hWnd;
5551     HANDLE handles[2];
5552     DWORD id;
5553 };
5554
5555 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT id, DWORD dwTime)
5556 {
5557 }
5558
5559 #define TIMER_ID  0x19
5560
5561 static DWORD WINAPI timer_thread_proc(LPVOID x)
5562 {
5563     struct timer_info *info = x;
5564     DWORD r;
5565
5566     r = KillTimer(info->hWnd, 0x19);
5567     ok(r,"KillTimer failed in thread\n");
5568     r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
5569     ok(r,"SetTimer failed in thread\n");
5570     ok(r==TIMER_ID,"SetTimer id different\n");
5571     r = SetEvent(info->handles[0]);
5572     ok(r,"SetEvent failed in thread\n");
5573     return 0;
5574 }
5575
5576 static void test_timers(void)
5577 {
5578     struct timer_info info;
5579     DWORD id;
5580
5581     info.hWnd = CreateWindow ("TestWindowClass", NULL,
5582        WS_OVERLAPPEDWINDOW ,
5583        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5584        NULL, NULL, 0);
5585
5586     info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
5587     ok(info.id, "SetTimer failed\n");
5588     ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
5589     info.handles[0] = CreateEvent(NULL,0,0,NULL);
5590     info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
5591
5592     WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
5593
5594     WaitForSingleObject(info.handles[1], INFINITE);
5595
5596     CloseHandle(info.handles[0]);
5597     CloseHandle(info.handles[1]);
5598
5599     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
5600
5601     ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
5602 }
5603
5604 /* Various win events with arbitrary parameters */
5605 static const struct message WmWinEventsSeq[] = {
5606     { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
5607     { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
5608     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
5609     { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
5610     { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
5611     { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
5612     { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
5613     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
5614     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
5615     /* our win event hook ignores OBJID_CURSOR events */
5616     /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
5617     { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
5618     { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
5619     { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
5620     { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
5621     { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
5622     { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
5623     { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
5624     { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
5625     { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
5626     { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
5627     { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
5628     { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
5629     { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
5630     { 0 }
5631 };
5632 static const struct message WmWinEventCaretSeq[] = {
5633     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
5634     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
5635     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
5636     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
5637     { 0 }
5638 };
5639 static const struct message WmWinEventCaretSeq_2[] = {
5640     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
5641     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
5642     { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
5643     { 0 }
5644 };
5645 static const struct message WmWinEventAlertSeq[] = {
5646     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
5647     { 0 }
5648 };
5649 static const struct message WmWinEventAlertSeq_2[] = {
5650     /* create window in the thread proc */
5651     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
5652     /* our test event */
5653     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
5654     { 0 }
5655 };
5656 static const struct message WmGlobalHookSeq_1[] = {
5657     /* create window in the thread proc */
5658     { HCBT_CREATEWND, hook|lparam, 0, 2 },
5659     /* our test events */
5660     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
5661     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
5662     { 0 }
5663 };
5664 static const struct message WmGlobalHookSeq_2[] = {
5665     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
5666     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
5667     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
5668     { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
5669     { 0 }
5670 };
5671
5672 static const struct message WmMouseLLHookSeq[] = {
5673     { WM_MOUSEMOVE, hook },
5674     { WM_LBUTTONDOWN, hook },
5675     { WM_LBUTTONUP, hook },
5676     { 0 }
5677 };
5678
5679 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
5680                                          DWORD event,
5681                                          HWND hwnd,
5682                                          LONG object_id,
5683                                          LONG child_id,
5684                                          DWORD thread_id,
5685                                          DWORD event_time)
5686 {
5687     char buf[256];
5688
5689     trace("WEH_2:%p,event %08lx,hwnd %p,obj %08lx,id %08lx,thread %08lx,time %08lx\n",
5690            hevent, event, hwnd, object_id, child_id, thread_id, event_time);
5691
5692     if (GetClassNameA(hwnd, buf, sizeof(buf)))
5693     {
5694         if (!lstrcmpiA(buf, "TestWindowClass") ||
5695             !lstrcmpiA(buf, "static"))
5696         {
5697             struct message msg;
5698
5699             msg.message = event;
5700             msg.flags = winevent_hook|wparam|lparam;
5701             msg.wParam = object_id;
5702             msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
5703             add_message(&msg);
5704         }
5705     }
5706 }
5707
5708 static HHOOK hCBT_global_hook;
5709 static DWORD cbt_global_hook_thread_id;
5710
5711 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
5712
5713     HWND hwnd;
5714     char buf[256];
5715
5716     trace("CBT_2: %d, %08x, %08lx\n", nCode, wParam, lParam);
5717
5718     if (nCode == HCBT_SYSCOMMAND)
5719     {
5720         struct message msg;
5721
5722         msg.message = nCode;
5723         msg.flags = hook|wparam|lparam;
5724         msg.wParam = wParam;
5725         msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
5726         add_message(&msg);
5727
5728         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
5729     }
5730     /* WH_MOUSE_LL hook */
5731     if (nCode == HC_ACTION)
5732     {
5733         struct message msg;
5734         MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
5735
5736         /* we can't test for real mouse events */
5737         if (mhll->flags & LLMHF_INJECTED)
5738         {
5739             msg.message = wParam;
5740             msg.flags = hook;
5741             add_message(&msg);
5742         }
5743         return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
5744     }
5745
5746     /* Log also SetFocus(0) calls */
5747     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
5748
5749     if (GetClassNameA(hwnd, buf, sizeof(buf)))
5750     {
5751         if (!lstrcmpiA(buf, "TestWindowClass") ||
5752             !lstrcmpiA(buf, "static"))
5753         {
5754             struct message msg;
5755
5756             msg.message = nCode;
5757             msg.flags = hook|wparam|lparam;
5758             msg.wParam = wParam;
5759             msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
5760             add_message(&msg);
5761         }
5762     }
5763     return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
5764 }
5765
5766 static DWORD WINAPI win_event_global_thread_proc(void *param)
5767 {
5768     HWND hwnd;
5769     MSG msg;
5770     HANDLE hevent = *(HANDLE *)param;
5771     HMODULE user32 = GetModuleHandleA("user32.dll");
5772     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
5773
5774     assert(pNotifyWinEvent);
5775
5776     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
5777     assert(hwnd);
5778     trace("created thread window %p\n", hwnd);
5779
5780     *(HWND *)param = hwnd;
5781
5782     flush_sequence();
5783     /* this event should be received only by our new hook proc,
5784      * an old one does not expect an event from another thread.
5785      */
5786     pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
5787     SetEvent(hevent);
5788
5789     while (GetMessage(&msg, 0, 0, 0))
5790     {
5791         TranslateMessage(&msg);
5792         DispatchMessage(&msg);
5793     }
5794     return 0;
5795 }
5796
5797 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
5798 {
5799     HWND hwnd;
5800     MSG msg;
5801     HANDLE hevent = *(HANDLE *)param;
5802
5803     flush_sequence();
5804     /* these events should be received only by our new hook proc,
5805      * an old one does not expect an event from another thread.
5806      */
5807
5808     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
5809     assert(hwnd);
5810     trace("created thread window %p\n", hwnd);
5811
5812     *(HWND *)param = hwnd;
5813
5814     /* Windows doesn't like when a thread plays games with the focus,
5815        that leads to all kinds of misbehaviours and failures to activate
5816        a window. So, better keep next lines commented out.
5817     SetFocus(0);
5818     SetFocus(hwnd);*/
5819
5820     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
5821     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
5822
5823     SetEvent(hevent);
5824
5825     while (GetMessage(&msg, 0, 0, 0))
5826     {
5827         TranslateMessage(&msg);
5828         DispatchMessage(&msg);
5829     }
5830     return 0;
5831 }
5832
5833 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
5834 {
5835     HWND hwnd;
5836     MSG msg;
5837     HANDLE hevent = *(HANDLE *)param;
5838
5839     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
5840     assert(hwnd);
5841     trace("created thread window %p\n", hwnd);
5842
5843     *(HWND *)param = hwnd;
5844
5845     flush_sequence();
5846
5847     mouse_event(MOUSEEVENTF_MOVE, 100, 0, 0, 0);
5848     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
5849     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
5850
5851     SetEvent(hevent);
5852     while (GetMessage(&msg, 0, 0, 0))
5853     {
5854         TranslateMessage(&msg);
5855         DispatchMessage(&msg);
5856     }
5857     return 0;
5858 }
5859
5860 static void test_winevents(void)
5861 {
5862     BOOL ret;
5863     MSG msg;
5864     HWND hwnd, hwnd2;
5865     UINT i;
5866     HANDLE hthread, hevent;
5867     DWORD tid;
5868     HWINEVENTHOOK hhook;
5869     const struct message *events = WmWinEventsSeq;
5870     HMODULE user32 = GetModuleHandleA("user32.dll");
5871     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
5872     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
5873     FARPROC pNotifyWinEvent = GetProcAddress(user32, "NotifyWinEvent");
5874
5875     hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
5876                            WS_OVERLAPPEDWINDOW,
5877                            CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5878                            NULL, NULL, 0);
5879     assert(hwnd);
5880
5881     /****** start of global hook test *************/
5882     hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
5883     assert(hCBT_global_hook);
5884
5885     hevent = CreateEventA(NULL, 0, 0, NULL);
5886     assert(hevent);
5887     hwnd2 = (HWND)hevent;
5888
5889     hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
5890     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5891
5892     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5893
5894     ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
5895
5896     flush_sequence();
5897     /* this one should be received only by old hook proc */
5898     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
5899     /* this one should be received only by old hook proc */
5900     DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
5901
5902     ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
5903
5904     ret = UnhookWindowsHookEx(hCBT_global_hook);
5905     ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
5906
5907     PostThreadMessageA(tid, WM_QUIT, 0, 0);
5908     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5909     CloseHandle(hthread);
5910     CloseHandle(hevent);
5911     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
5912     /****** end of global hook test *************/
5913
5914     if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
5915     {
5916         ok(DestroyWindow(hwnd), "failed to destroy window\n");
5917         return;
5918     }
5919
5920     flush_sequence();
5921
5922 #if 0 /* this test doesn't pass under Win9x */
5923     /* win2k ignores events with hwnd == 0 */
5924     SetLastError(0xdeadbeef);
5925     pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
5926     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
5927        GetLastError() == 0xdeadbeef, /* Win9x */
5928        "unexpected error %ld\n", GetLastError());
5929     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
5930 #endif
5931
5932     for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
5933         pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
5934
5935     ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
5936
5937     /****** start of event filtering test *************/
5938     hhook = (HWINEVENTHOOK)pSetWinEventHook(
5939         EVENT_OBJECT_SHOW, /* 0x8002 */
5940         EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
5941         GetModuleHandleA(0), win_event_global_hook_proc,
5942         GetCurrentProcessId(), 0,
5943         WINEVENT_INCONTEXT);
5944     ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
5945
5946     hevent = CreateEventA(NULL, 0, 0, NULL);
5947     assert(hevent);
5948     hwnd2 = (HWND)hevent;
5949
5950     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
5951     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5952
5953     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5954
5955     ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
5956
5957     flush_sequence();
5958     /* this one should be received only by old hook proc */
5959     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
5960     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
5961     /* this one should be received only by old hook proc */
5962     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
5963
5964     ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
5965
5966     ret = pUnhookWinEvent(hhook);
5967     ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
5968
5969     PostThreadMessageA(tid, WM_QUIT, 0, 0);
5970     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5971     CloseHandle(hthread);
5972     CloseHandle(hevent);
5973     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
5974     /****** end of event filtering test *************/
5975
5976     /****** start of out of context event test *************/
5977     hhook = (HWINEVENTHOOK)pSetWinEventHook(
5978         EVENT_MIN, EVENT_MAX,
5979         0, win_event_global_hook_proc,
5980         GetCurrentProcessId(), 0,
5981         WINEVENT_OUTOFCONTEXT);
5982     ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError());
5983
5984     hevent = CreateEventA(NULL, 0, 0, NULL);
5985     assert(hevent);
5986     hwnd2 = (HWND)hevent;
5987
5988     flush_sequence();
5989
5990     hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
5991     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
5992
5993     ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5994
5995     ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
5996     /* process pending winevent messages */
5997     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
5998     ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
5999
6000     flush_sequence();
6001     /* this one should be received only by old hook proc */
6002     pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
6003     pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
6004     /* this one should be received only by old hook proc */
6005     pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
6006
6007     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
6008     /* process pending winevent messages */
6009     ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
6010     ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
6011
6012     ret = pUnhookWinEvent(hhook);
6013     ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
6014
6015     PostThreadMessageA(tid, WM_QUIT, 0, 0);
6016     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6017     CloseHandle(hthread);
6018     CloseHandle(hevent);
6019     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
6020     /****** end of out of context event test *************/
6021
6022     /****** start of MOUSE_LL hook test *************/
6023     hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
6024     assert(hCBT_global_hook);
6025
6026     hevent = CreateEventA(NULL, 0, 0, NULL);
6027     assert(hevent);
6028     hwnd2 = (HWND)hevent;
6029
6030     hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
6031     ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError());
6032
6033     while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
6034         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6035
6036     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
6037     flush_sequence();
6038
6039     mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0);
6040     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
6041     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
6042
6043     ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
6044
6045     ret = UnhookWindowsHookEx(hCBT_global_hook);
6046     ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError());
6047
6048     PostThreadMessageA(tid, WM_QUIT, 0, 0);
6049     ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
6050     CloseHandle(hthread);
6051     CloseHandle(hevent);
6052     ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
6053     /****** end of MOUSE_LL hook test *************/
6054
6055     ok(DestroyWindow(hwnd), "failed to destroy window\n");
6056 }
6057
6058 static void test_set_hook(void)
6059 {
6060     BOOL ret;
6061     HHOOK hhook;
6062     HWINEVENTHOOK hwinevent_hook;
6063     HMODULE user32 = GetModuleHandleA("user32.dll");
6064     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
6065     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
6066
6067     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
6068     ok(hhook != 0, "local hook does not require hModule set to 0\n");
6069     UnhookWindowsHookEx(hhook);
6070
6071 #if 0 /* this test doesn't pass under Win9x: BUG! */
6072     SetLastError(0xdeadbeef);
6073     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
6074     ok(!hhook, "global hook requires hModule != 0\n");
6075     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError());
6076 #endif
6077
6078     SetLastError(0xdeadbeef);
6079     hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
6080     ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
6081     ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
6082        GetLastError() == 0xdeadbeef, /* Win9x */
6083        "unexpected error %ld\n", GetLastError());
6084
6085     SetLastError(0xdeadbeef);
6086     ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
6087     ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
6088        GetLastError() == 0xdeadbeef, /* Win9x */
6089        "unexpected error %ld\n", GetLastError());
6090
6091     if (!pSetWinEventHook || !pUnhookWinEvent) return;
6092
6093     /* even process local incontext hooks require hmodule */
6094     SetLastError(0xdeadbeef);
6095     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
6096         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
6097     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
6098     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
6099        GetLastError() == 0xdeadbeef, /* Win9x */
6100        "unexpected error %ld\n", GetLastError());
6101
6102     /* even thread local incontext hooks require hmodule */
6103     SetLastError(0xdeadbeef);
6104     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
6105         0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
6106     ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
6107     ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
6108        GetLastError() == 0xdeadbeef, /* Win9x */
6109        "unexpected error %ld\n", GetLastError());
6110
6111 #if 0 /* these 3 tests don't pass under Win9x */
6112     SetLastError(0xdeadbeef);
6113     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0,
6114         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
6115     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
6116     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
6117
6118     SetLastError(0xdeadbeef);
6119     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1,
6120         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
6121     ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
6122     ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError());
6123
6124     SetLastError(0xdeadbeef);
6125     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
6126         0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
6127     ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
6128     ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError());
6129 #endif
6130
6131     SetLastError(0xdeadbeef);
6132     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0,
6133         0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
6134     ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
6135     ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
6136     ret = pUnhookWinEvent(hwinevent_hook);
6137     ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
6138
6139 todo_wine {
6140     /* This call succeeds under win2k SP4, but fails under Wine.
6141        Does win2k test/use passed process id? */
6142     SetLastError(0xdeadbeef);
6143     hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
6144         0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
6145     ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError());
6146     ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError());
6147     ret = pUnhookWinEvent(hwinevent_hook);
6148     ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
6149 }
6150
6151     SetLastError(0xdeadbeef);
6152     ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
6153     ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
6154         GetLastError() == 0xdeadbeef, /* Win9x */
6155         "unexpected error %ld\n", GetLastError());
6156 }
6157
6158 static const struct message ScrollWindowPaint1[] = {
6159     { WM_PAINT, sent },
6160     { WM_ERASEBKGND, sent|beginpaint },
6161     { 0 }
6162 };
6163
6164 static const struct message ScrollWindowPaint2[] = {
6165     { WM_PAINT, sent },
6166     { 0 }
6167 };
6168
6169 static void test_scrollwindowex(void)
6170 {
6171     HWND hwnd, hchild;
6172     RECT rect={0,0,130,130};
6173     MSG msg;
6174
6175     hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
6176             WS_VISIBLE|WS_OVERLAPPEDWINDOW,
6177             100, 100, 200, 200, 0, 0, 0, NULL);
6178     ok (hwnd != 0, "Failed to create overlapped window\n");
6179     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", 
6180             WS_VISIBLE|WS_CAPTION|WS_CHILD,
6181             10, 10, 150, 150, hwnd, 0, 0, NULL);
6182     ok (hchild != 0, "Failed to create child\n");
6183     UpdateWindow(hwnd);
6184     flush_events();
6185     flush_sequence();
6186
6187     /* scroll without the child window */
6188     trace("start scroll\n");
6189     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
6190             SW_ERASE|SW_INVALIDATE);
6191     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
6192     trace("end scroll\n");
6193     flush_sequence();
6194     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6195     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
6196
6197     /* Now without the SW_ERASE flag */
6198     trace("start scroll\n");
6199     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
6200     ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
6201     trace("end scroll\n");
6202     flush_sequence();
6203     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6204     ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", 0);
6205
6206     /* now scroll the child window as well */
6207     trace("start scroll\n");
6208     ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
6209             SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
6210     todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
6211                 /* windows sometimes a WM_MOVE */
6212         ok_sequence(WmEmptySeq, "ScrollWindowEx", 0);
6213     }
6214     trace("end scroll\n");
6215     flush_sequence();
6216     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6217     ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", 0);
6218
6219     /* now scroll with ScrollWindow() */
6220     trace("start scroll with ScrollWindow\n");
6221     ScrollWindow( hwnd, 5, 5, NULL, NULL);
6222     trace("end scroll\n");
6223     flush_sequence();
6224     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6225     ok_sequence(ScrollWindowPaint1, "ScrollWindow", 0);
6226
6227     ok(DestroyWindow(hchild), "failed to destroy window\n");
6228     ok(DestroyWindow(hwnd), "failed to destroy window\n");
6229     flush_sequence();
6230 }
6231
6232 static const struct message destroy_window_with_children[] = {
6233     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
6234     { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
6235     { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
6236     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
6237     { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
6238     { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
6239     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
6240     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
6241     { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
6242     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
6243     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
6244     { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
6245     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
6246     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
6247     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
6248     { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
6249     { 0 }
6250 };
6251
6252 static void test_DestroyWindow(void)
6253 {
6254     BOOL ret;
6255     HWND parent, child1, child2, child3, child4, test;
6256     UINT child_id = WND_CHILD_ID + 1;
6257
6258     parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6259                              100, 100, 200, 200, 0, 0, 0, NULL);
6260     assert(parent != 0);
6261     child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
6262                              0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
6263     assert(child1 != 0);
6264     child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
6265                              0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
6266     assert(child2 != 0);
6267     child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
6268                              0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
6269     assert(child3 != 0);
6270     child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
6271                              0, 0, 50, 50, parent, 0, 0, NULL);
6272     assert(child4 != 0);
6273
6274     /* test owner/parent of child2 */
6275     test = GetParent(child2);
6276     ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
6277     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
6278     if(pGetAncestor) {
6279         test = pGetAncestor(child2, GA_PARENT);
6280         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
6281     }
6282     test = GetWindow(child2, GW_OWNER);
6283     ok(!test, "wrong owner %p\n", test);
6284
6285     test = SetParent(child2, parent);
6286     ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
6287
6288     /* test owner/parent of the parent */
6289     test = GetParent(parent);
6290     ok(!test, "wrong parent %p\n", test);
6291 todo_wine {
6292     ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
6293 }
6294     if(pGetAncestor) {
6295         test = pGetAncestor(parent, GA_PARENT);
6296         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
6297     }
6298     test = GetWindow(parent, GW_OWNER);
6299     ok(!test, "wrong owner %p\n", test);
6300
6301     /* test owner/parent of child1 */
6302     test = GetParent(child1);
6303     ok(test == parent, "wrong parent %p\n", test);
6304     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
6305     if(pGetAncestor) {
6306         test = pGetAncestor(child1, GA_PARENT);
6307         ok(test == parent, "wrong parent %p\n", test);
6308     }
6309     test = GetWindow(child1, GW_OWNER);
6310     ok(!test, "wrong owner %p\n", test);
6311
6312     /* test owner/parent of child2 */
6313     test = GetParent(child2);
6314     ok(test == parent, "wrong parent %p\n", test);
6315     ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
6316     if(pGetAncestor) {
6317         test = pGetAncestor(child2, GA_PARENT);
6318         ok(test == parent, "wrong parent %p\n", test);
6319     }
6320     test = GetWindow(child2, GW_OWNER);
6321     ok(!test, "wrong owner %p\n", test);
6322
6323     /* test owner/parent of child3 */
6324     test = GetParent(child3);
6325     ok(test == child1, "wrong parent %p\n", test);
6326     ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
6327     if(pGetAncestor) {
6328         test = pGetAncestor(child3, GA_PARENT);
6329         ok(test == child1, "wrong parent %p\n", test);
6330     }
6331     test = GetWindow(child3, GW_OWNER);
6332     ok(!test, "wrong owner %p\n", test);
6333
6334     /* test owner/parent of child4 */
6335     test = GetParent(child4);
6336     ok(test == parent, "wrong parent %p\n", test);
6337     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
6338     if(pGetAncestor) {
6339         test = pGetAncestor(child4, GA_PARENT);
6340         ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
6341     }
6342     test = GetWindow(child4, GW_OWNER);
6343     ok(test == parent, "wrong owner %p\n", test);
6344
6345     flush_sequence();
6346
6347     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
6348            parent, child1, child2, child3, child4);
6349
6350     SetCapture(child4);
6351     test = GetCapture();
6352     ok(test == child4, "wrong capture window %p\n", test);
6353
6354     test_DestroyWindow_flag = TRUE;
6355     ret = DestroyWindow(parent);
6356     ok( ret, "DestroyWindow() error %ld\n", GetLastError());
6357     test_DestroyWindow_flag = FALSE;
6358     ok_sequence(destroy_window_with_children, "destroy window with children", 0);
6359
6360     ok(!IsWindow(parent), "parent still exists\n");
6361     ok(!IsWindow(child1), "child1 still exists\n");
6362     ok(!IsWindow(child2), "child2 still exists\n");
6363     ok(!IsWindow(child3), "child3 still exists\n");
6364     ok(!IsWindow(child4), "child4 still exists\n");
6365
6366     test = GetCapture();
6367     ok(!test, "wrong capture window %p\n", test);
6368 }
6369
6370
6371 static const struct message WmDispatchPaint[] = {
6372     { WM_NCPAINT, sent },
6373     { WM_GETTEXT, sent|defwinproc|optional },
6374     { WM_GETTEXT, sent|defwinproc|optional },
6375     { WM_ERASEBKGND, sent },
6376     { 0 }
6377 };
6378
6379 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6380 {
6381     if (message == WM_PAINT) return 0;
6382     return MsgCheckProcA( hwnd, message, wParam, lParam );
6383 }
6384
6385 static void test_DispatchMessage(void)
6386 {
6387     RECT rect;
6388     MSG msg;
6389     int count;
6390     HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6391                                100, 100, 200, 200, 0, 0, 0, NULL);
6392     ShowWindow( hwnd, SW_SHOW );
6393     UpdateWindow( hwnd );
6394     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6395     flush_sequence();
6396     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
6397
6398     SetRect( &rect, -5, -5, 5, 5 );
6399     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
6400     count = 0;
6401     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6402     {
6403         if (msg.message != WM_PAINT) DispatchMessage( &msg );
6404         else
6405         {
6406             flush_sequence();
6407             DispatchMessage( &msg );
6408             /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
6409             if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
6410             else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
6411             if (++count > 10) break;
6412         }
6413     }
6414     ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
6415
6416     trace("now without DispatchMessage\n");
6417     flush_sequence();
6418     RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
6419     count = 0;
6420     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
6421     {
6422         if (msg.message != WM_PAINT) DispatchMessage( &msg );
6423         else
6424         {
6425             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
6426             flush_sequence();
6427             /* this will send WM_NCCPAINT just like DispatchMessage does */
6428             GetUpdateRgn( hwnd, hrgn, TRUE );
6429             ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
6430             DeleteObject( hrgn );
6431             GetClientRect( hwnd, &rect );
6432             ValidateRect( hwnd, &rect );  /* this will stop WM_PAINTs */
6433             ok( !count, "Got multiple WM_PAINTs\n" );
6434             if (++count > 10) break;
6435         }
6436     }
6437     DestroyWindow(hwnd);
6438 }
6439
6440
6441 static const struct message WmUser[] = {
6442     { WM_USER, sent },
6443     { 0 }
6444 };
6445
6446 struct sendmsg_info
6447 {
6448     HWND  hwnd;
6449     DWORD timeout;
6450     DWORD ret;
6451 };
6452
6453 static DWORD CALLBACK send_msg_thread( LPVOID arg )
6454 {
6455     struct sendmsg_info *info = arg;
6456     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
6457     if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %ld\n", GetLastError());
6458     return 0;
6459 }
6460
6461 static void wait_for_thread( HANDLE thread )
6462 {
6463     while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
6464     {
6465         MSG msg;
6466         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage(&msg);
6467     }
6468 }
6469
6470 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6471 {
6472     if (message == WM_USER) Sleep(200);
6473     return MsgCheckProcA( hwnd, message, wParam, lParam );
6474 }
6475
6476 static void test_SendMessageTimeout(void)
6477 {
6478     MSG msg;
6479     HANDLE thread;
6480     struct sendmsg_info info;
6481     DWORD tid;
6482
6483     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6484                                100, 100, 200, 200, 0, 0, 0, NULL);
6485     while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
6486     flush_sequence();
6487
6488     info.timeout = 1000;
6489     info.ret = 0xdeadbeef;
6490     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
6491     wait_for_thread( thread );
6492     CloseHandle( thread );
6493     ok( info.ret == 1, "SendMessageTimeout failed\n" );
6494     ok_sequence( WmUser, "WmUser", FALSE );
6495
6496     info.timeout = 1;
6497     info.ret = 0xdeadbeef;
6498     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
6499     Sleep(100);  /* SendMessageTimeout should timeout here */
6500     wait_for_thread( thread );
6501     CloseHandle( thread );
6502     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
6503     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6504
6505     /* 0 means infinite timeout */
6506     info.timeout = 0;
6507     info.ret = 0xdeadbeef;
6508     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
6509     Sleep(100);
6510     wait_for_thread( thread );
6511     CloseHandle( thread );
6512     ok( info.ret == 1, "SendMessageTimeout failed\n" );
6513     ok_sequence( WmUser, "WmUser", FALSE );
6514
6515     /* timeout is treated as signed despite the prototype */
6516     info.timeout = 0x7fffffff;
6517     info.ret = 0xdeadbeef;
6518     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
6519     Sleep(100);
6520     wait_for_thread( thread );
6521     CloseHandle( thread );
6522     ok( info.ret == 1, "SendMessageTimeout failed\n" );
6523     ok_sequence( WmUser, "WmUser", FALSE );
6524
6525     info.timeout = 0x80000000;
6526     info.ret = 0xdeadbeef;
6527     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
6528     Sleep(100);
6529     wait_for_thread( thread );
6530     CloseHandle( thread );
6531     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
6532     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
6533
6534     /* now check for timeout during message processing */
6535     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
6536     info.timeout = 100;
6537     info.ret = 0xdeadbeef;
6538     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
6539     wait_for_thread( thread );
6540     CloseHandle( thread );
6541     /* we should timeout but still get the message */
6542     ok( info.ret == 0, "SendMessageTimeout failed\n" );
6543     ok_sequence( WmUser, "WmUser", FALSE );
6544
6545     DestroyWindow( info.hwnd );
6546 }
6547
6548
6549 /****************** edit message test *************************/
6550 #define ID_EDIT 0x1234
6551 static const struct message sl_edit_setfocus[] =
6552 {
6553     { HCBT_SETFOCUS, hook },
6554     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6555     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6556     { WM_SETFOCUS, sent|wparam, 0 },
6557     { WM_CTLCOLOREDIT, sent|parent },
6558     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6559     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6560     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
6561     { 0 }
6562 };
6563 static const struct message ml_edit_setfocus[] =
6564 {
6565     { HCBT_SETFOCUS, hook },
6566     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
6567     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6568     { WM_SETFOCUS, sent|wparam, 0 },
6569     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6570     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6571     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6572     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
6573     { 0 }
6574 };
6575 static const struct message sl_edit_killfocus[] =
6576 {
6577     { HCBT_SETFOCUS, hook },
6578     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6579     { WM_KILLFOCUS, sent|wparam, 0 },
6580     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6581     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6582     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
6583     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
6584     { 0 }
6585 };
6586 static const struct message sl_edit_lbutton_dblclk[] =
6587 {
6588     { WM_LBUTTONDBLCLK, sent },
6589     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6590     { 0 }
6591 };
6592 static const struct message sl_edit_lbutton_down[] =
6593 {
6594     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6595     { HCBT_SETFOCUS, hook },
6596     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6597     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6598     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6599     { WM_CTLCOLOREDIT, sent|parent },
6600     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6601     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6602     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6603     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
6604     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6605     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6606     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6607     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6608     { 0 }
6609 };
6610 static const struct message ml_edit_lbutton_down[] =
6611 {
6612     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
6613     { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6614     { HCBT_SETFOCUS, hook },
6615     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
6616     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6617     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
6618     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6619     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6620     { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
6621     { 0 }
6622 };
6623 static const struct message sl_edit_lbutton_up[] =
6624 {
6625     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6626     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6627     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6628     { WM_CAPTURECHANGED, sent|defwinproc },
6629     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
6630     { 0 }
6631 };
6632 static const struct message ml_edit_lbutton_up[] =
6633 {
6634     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6635     { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6636     { WM_CAPTURECHANGED, sent|defwinproc },
6637     { 0 }
6638 };
6639
6640 static WNDPROC old_edit_proc;
6641
6642 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6643 {
6644     static long defwndproc_counter = 0;
6645     LRESULT ret;
6646     struct message msg;
6647
6648     trace("edit: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
6649
6650     /* explicitly ignore WM_GETICON message */
6651     if (message == WM_GETICON) return 0;
6652
6653     msg.message = message;
6654     msg.flags = sent|wparam|lparam;
6655     if (defwndproc_counter) msg.flags |= defwinproc;
6656     msg.wParam = wParam;
6657     msg.lParam = lParam;
6658     add_message(&msg);
6659
6660     defwndproc_counter++;
6661     ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
6662     defwndproc_counter--;
6663
6664     return ret;
6665 }
6666
6667 static void subclass_edit(void)
6668 {
6669     WNDCLASSA cls;
6670
6671     if (!GetClassInfoA(0, "edit", &cls)) assert(0);
6672
6673     old_edit_proc = cls.lpfnWndProc;
6674
6675     cls.hInstance = GetModuleHandle(0);
6676     cls.lpfnWndProc = edit_hook_proc;
6677     cls.lpszClassName = "my_edit_class";
6678     if (!RegisterClassA(&cls)) assert(0);
6679 }
6680
6681 static void test_edit_messages(void)
6682 {
6683     HWND hwnd, parent;
6684     DWORD dlg_code;
6685
6686     subclass_edit();
6687     log_all_parent_messages++;
6688
6689     parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6690                              100, 100, 200, 200, 0, 0, 0, NULL);
6691     ok (parent != 0, "Failed to create parent window\n");
6692
6693     /* test single line edit */
6694     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
6695                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
6696     ok(hwnd != 0, "Failed to create edit window\n");
6697
6698     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6699     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08lx\n", dlg_code);
6700
6701     ShowWindow(hwnd, SW_SHOW);
6702     UpdateWindow(hwnd);
6703     SetFocus(0);
6704     flush_sequence();
6705
6706     SetFocus(hwnd);
6707     ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
6708
6709     SetFocus(0);
6710     ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
6711
6712     SetFocus(0);
6713     ReleaseCapture();
6714     flush_sequence();
6715
6716     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
6717     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
6718
6719     SetFocus(0);
6720     ReleaseCapture();
6721     flush_sequence();
6722
6723     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6724     ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
6725
6726     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6727     ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
6728
6729     DestroyWindow(hwnd);
6730
6731     /* test multiline edit */
6732     hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
6733                            0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
6734     ok(hwnd != 0, "Failed to create edit window\n");
6735
6736     dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6737     ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
6738        "wrong dlg_code %08lx\n", dlg_code);
6739
6740     ShowWindow(hwnd, SW_SHOW);
6741     UpdateWindow(hwnd);
6742     SetFocus(0);
6743     flush_sequence();
6744
6745     SetFocus(hwnd);
6746     ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
6747
6748     SetFocus(0);
6749     ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
6750
6751     SetFocus(0);
6752     ReleaseCapture();
6753     flush_sequence();
6754
6755     SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
6756     ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
6757
6758     SetFocus(0);
6759     ReleaseCapture();
6760     flush_sequence();
6761
6762     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6763     ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
6764
6765     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6766     ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
6767
6768     DestroyWindow(hwnd);
6769     DestroyWindow(parent);
6770
6771     log_all_parent_messages--;
6772 }
6773
6774 /**************************** End of Edit test ******************************/
6775
6776 static const struct message WmChar[] = {
6777     { WM_CHAR, sent|wparam, 'z' },
6778     { 0 }
6779 };
6780
6781 static const struct message WmKeyDownUp[] = {
6782     { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x00000001 },
6783     { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
6784     { 0 }
6785 };
6786
6787 static const struct message WmUserChar[] = {
6788     { WM_USER, sent },
6789     { WM_CHAR, sent|wparam, 'z' },
6790     { 0 }
6791 };
6792
6793 #define EV_START_STOP 0
6794 #define EV_SENDMSG 1
6795 #define EV_ACK 2
6796
6797 struct peekmsg_info
6798 {
6799     HWND  hwnd;
6800     HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
6801 };
6802
6803 static DWORD CALLBACK send_msg_thread_2(void *param)
6804 {
6805     DWORD ret;
6806     struct peekmsg_info *info = param;
6807
6808     trace("thread: waiting for start\n");
6809     WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
6810     trace("thread: looping\n");
6811
6812     while (1)
6813     {
6814         ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
6815
6816         switch (ret)
6817         {
6818         case WAIT_OBJECT_0 + EV_START_STOP:
6819             trace("thread: exiting\n");
6820             return 0;
6821
6822         case WAIT_OBJECT_0 + EV_SENDMSG:
6823             trace("thread: sending message\n");
6824             SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
6825             SetEvent(info->hevent[EV_ACK]);
6826             break;
6827
6828         default:
6829             trace("unexpected return: %04lx\n", ret);
6830             assert(0);
6831             break;
6832         }
6833     }
6834     return 0;
6835 }
6836
6837 static void test_PeekMessage(void)
6838 {
6839     MSG msg;
6840     HANDLE hthread;
6841     DWORD tid, qstatus;
6842     UINT qs_all_input = QS_ALLINPUT;
6843     UINT qs_input = QS_INPUT;
6844     struct peekmsg_info info;
6845
6846     info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
6847                               100, 100, 200, 200, 0, 0, 0, NULL);
6848     ShowWindow(info.hwnd, SW_SHOW);
6849     UpdateWindow(info.hwnd);
6850
6851     info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
6852     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
6853     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
6854
6855     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
6856
6857     trace("signalling to start looping\n");
6858     SetEvent(info.hevent[EV_START_STOP]);
6859
6860     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6861     flush_sequence();
6862
6863     SetLastError(0xdeadbeef);
6864     qstatus = GetQueueStatus(qs_all_input);
6865     if (GetLastError() == ERROR_INVALID_FLAGS)
6866     {
6867         trace("QS_RAWINPUT not supported on this platform\n");
6868         qs_all_input &= ~QS_RAWINPUT;
6869         qs_input &= ~QS_RAWINPUT;
6870     }
6871     ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
6872
6873     trace("signalling to send message\n");
6874     SetEvent(info.hevent[EV_SENDMSG]);
6875     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
6876
6877     /* pass invalid QS_xxxx flags */
6878     SetLastError(0xdeadbeef);
6879     qstatus = GetQueueStatus(0xffffffff);
6880     ok(qstatus == 0, "GetQueueStatus should fail: %08lx\n", qstatus);
6881     ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %ld\n", GetLastError());
6882
6883     qstatus = GetQueueStatus(qs_all_input);
6884     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
6885        "wrong qstatus %08lx\n", qstatus);
6886
6887     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6888     ok_sequence(WmUser, "WmUser", FALSE);
6889
6890     qstatus = GetQueueStatus(qs_all_input);
6891     ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus);
6892
6893     keybd_event('N', 0, 0, 0);
6894     keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
6895     qstatus = GetQueueStatus(qs_all_input);
6896     ok(qstatus == MAKELONG(QS_KEY, QS_KEY),
6897        "wrong qstatus %08lx\n", qstatus);
6898
6899     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
6900     qstatus = GetQueueStatus(qs_all_input);
6901     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
6902        "wrong qstatus %08lx\n", qstatus);
6903
6904     InvalidateRect(info.hwnd, NULL, FALSE);
6905     qstatus = GetQueueStatus(qs_all_input);
6906     ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
6907        "wrong qstatus %08lx\n", qstatus);
6908
6909     trace("signalling to send message\n");
6910     SetEvent(info.hevent[EV_SENDMSG]);
6911     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
6912
6913     qstatus = GetQueueStatus(qs_all_input);
6914     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
6915        "wrong qstatus %08lx\n", qstatus);
6916     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16))) DispatchMessageA(&msg);
6917     ok_sequence(WmUser, "WmUser", TRUE); /* todo_wine */
6918
6919     qstatus = GetQueueStatus(qs_all_input);
6920 todo_wine {
6921     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
6922        "wrong qstatus %08lx\n", qstatus);
6923 }
6924
6925     trace("signalling to send message\n");
6926     SetEvent(info.hevent[EV_SENDMSG]);
6927     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
6928
6929     qstatus = GetQueueStatus(qs_all_input);
6930 todo_wine {
6931     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
6932        "wrong qstatus %08lx\n", qstatus);
6933 }
6934     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE)) DispatchMessageA(&msg);
6935     ok_sequence(WmUser, "WmUser", FALSE);
6936
6937     qstatus = GetQueueStatus(qs_all_input);
6938 todo_wine {
6939     ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
6940        "wrong qstatus %08lx\n", qstatus);
6941 }
6942
6943     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE)) DispatchMessageA(&msg);
6944     ok_sequence(WmChar, "WmChar", TRUE); /* todo_wine */
6945
6946     qstatus = GetQueueStatus(qs_all_input);
6947 todo_wine {
6948     ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
6949        "wrong qstatus %08lx\n", qstatus);
6950 }
6951
6952     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT)) DispatchMessageA(&msg);
6953     ok_sequence(WmPaint, "WmPaint", TRUE); /* todo_wine */
6954
6955     qstatus = GetQueueStatus(qs_all_input);
6956 todo_wine {
6957     ok(qstatus == MAKELONG(0, QS_KEY),
6958        "wrong qstatus %08lx\n", qstatus);
6959 }
6960
6961     trace("signalling to send message\n");
6962     SetEvent(info.hevent[EV_SENDMSG]);
6963     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
6964
6965     qstatus = GetQueueStatus(qs_all_input);
6966 todo_wine {
6967     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
6968        "wrong qstatus %08lx\n", qstatus);
6969 }
6970
6971     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
6972
6973     qstatus = GetQueueStatus(qs_all_input);
6974 todo_wine {
6975     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
6976        "wrong qstatus %08lx\n", qstatus);
6977 }
6978
6979     while (PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE)) DispatchMessage(&msg);
6980     ok_sequence(WmUserChar, "WmUserChar", FALSE);
6981
6982     qstatus = GetQueueStatus(qs_all_input);
6983 todo_wine {
6984     ok(qstatus == MAKELONG(0, QS_KEY),
6985        "wrong qstatus %08lx\n", qstatus);
6986 }
6987
6988     PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
6989
6990     qstatus = GetQueueStatus(qs_all_input);
6991 todo_wine {
6992     ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
6993        "wrong qstatus %08lx\n", qstatus);
6994 }
6995
6996     trace("signalling to send message\n");
6997     SetEvent(info.hevent[EV_SENDMSG]);
6998     WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
6999
7000     qstatus = GetQueueStatus(qs_all_input);
7001 todo_wine {
7002     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
7003        "wrong qstatus %08lx\n", qstatus);
7004 }
7005
7006     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16))) DispatchMessage(&msg);
7007     ok_sequence(WmUser, "WmUser", TRUE); /* todo_wine */
7008
7009     qstatus = GetQueueStatus(qs_all_input);
7010 todo_wine {
7011     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
7012        "wrong qstatus %08lx\n", qstatus);
7013 }
7014
7015     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16))) DispatchMessage(&msg);
7016     ok_sequence(WmKeyDownUp, "WmKeyDownUp", TRUE); /* todo_wine */
7017
7018     qstatus = GetQueueStatus(qs_all_input);
7019 todo_wine {
7020     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
7021        "wrong qstatus %08lx\n", qstatus);
7022 }
7023
7024     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE)) DispatchMessage(&msg);
7025     ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
7026
7027     qstatus = GetQueueStatus(qs_all_input);
7028 todo_wine {
7029     ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
7030        "wrong qstatus %08lx\n", qstatus);
7031 }
7032
7033     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7034     ok_sequence(WmChar, "WmChar", TRUE); /* todo_wine */
7035
7036     qstatus = GetQueueStatus(qs_all_input);
7037     ok(qstatus == 0,
7038        "wrong qstatus %08lx\n", qstatus);
7039
7040     trace("signalling to exit\n");
7041     SetEvent(info.hevent[EV_START_STOP]);
7042
7043     WaitForSingleObject(hthread, INFINITE);
7044
7045     CloseHandle(hthread);
7046     CloseHandle(info.hevent[0]);
7047     CloseHandle(info.hevent[1]);
7048     CloseHandle(info.hevent[2]);
7049
7050     DestroyWindow(info.hwnd);
7051 }
7052
7053
7054 static void test_quit_message(void)
7055 {
7056     MSG msg;
7057     BOOL ret;
7058
7059     /* test using PostQuitMessage */
7060     PostQuitMessage(0xbeef);
7061
7062     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
7063     ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
7064     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
7065     ok(msg.wParam == 0xbeef, "wParam was 0x%x instead of 0xbeef\n", msg.wParam);
7066
7067     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
7068     ok(ret, "PostMessage failed with error %ld\n", GetLastError());
7069
7070     ret = GetMessage(&msg, NULL, 0, 0);
7071     ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
7072     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
7073
7074     /* note: WM_QUIT message received after WM_USER message */
7075     ret = GetMessage(&msg, NULL, 0, 0);
7076     ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
7077     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
7078     ok(msg.wParam == 0xbeef, "wParam was 0x%x instead of 0xbeef\n", msg.wParam);
7079
7080     ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
7081     ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
7082
7083     /* now test with PostThreadMessage - different behaviour! */
7084     PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
7085
7086     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
7087     ok(ret, "PeekMessage failed with error %ld\n", GetLastError());
7088     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
7089     ok(msg.wParam == 0xdead, "wParam was 0x%x instead of 0xdead\n", msg.wParam);
7090
7091     ret = PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
7092     ok(ret, "PostMessage failed with error %ld\n", GetLastError());
7093
7094     /* note: we receive the WM_QUIT message first this time */
7095     ret = GetMessage(&msg, NULL, 0, 0);
7096     ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError());
7097     ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
7098     ok(msg.wParam == 0xdead, "wParam was 0x%x instead of 0xdead\n", msg.wParam);
7099
7100     ret = GetMessage(&msg, NULL, 0, 0);
7101     ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError());
7102     ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
7103 }
7104
7105 START_TEST(msg)
7106 {
7107     BOOL ret;
7108     HMODULE user32 = GetModuleHandleA("user32.dll");
7109     FARPROC pSetWinEventHook = GetProcAddress(user32, "SetWinEventHook");
7110     FARPROC pUnhookWinEvent = GetProcAddress(user32, "UnhookWinEvent");
7111     FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
7112     pGetAncestor = (void*) GetProcAddress(user32, "GetAncestor");
7113
7114     if (!RegisterWindowClasses()) assert(0);
7115
7116     if (pSetWinEventHook)
7117     {
7118         hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX,
7119                                                       GetModuleHandleA(0),
7120                                                       win_event_proc,
7121                                                       0,
7122                                                       GetCurrentThreadId(),
7123                                                       WINEVENT_INCONTEXT);
7124         assert(hEvent_hook);
7125
7126         if (pIsWinEventHookInstalled)
7127         {
7128             UINT event;
7129             for (event = EVENT_MIN; event <= EVENT_MAX; event++)
7130                 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
7131         }
7132     }
7133
7134     cbt_hook_thread_id = GetCurrentThreadId();
7135     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
7136     assert(hCBT_hook);
7137
7138     test_winevents();
7139
7140     /* Fix message sequences before removing 4 lines below */
7141 #if 1
7142     ret = pUnhookWinEvent(hEvent_hook);
7143     ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
7144     pUnhookWinEvent = 0;
7145     hEvent_hook = 0;
7146 #endif
7147
7148     test_PeekMessage();
7149     test_scrollwindowex();
7150     test_messages();
7151     test_mdi_messages();
7152     test_button_messages();
7153     test_paint_messages();
7154     test_interthread_messages();
7155     test_message_conversion();
7156     test_accelerators();
7157     test_timers();
7158     test_set_hook();
7159     test_DestroyWindow();
7160     test_DispatchMessage();
7161     test_SendMessageTimeout();
7162     test_edit_messages();
7163     test_quit_message();
7164
7165     UnhookWindowsHookEx(hCBT_hook);
7166     if (pUnhookWinEvent)
7167     {
7168         ret = pUnhookWinEvent(hEvent_hook);
7169         ok( ret, "UnhookWinEvent error %ld\n", GetLastError());
7170         SetLastError(0xdeadbeef);
7171         ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
7172         ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
7173            GetLastError() == 0xdeadbeef, /* Win9x */
7174            "unexpected error %ld\n", GetLastError());
7175     }
7176 }