Fix signed/unsigned comparison warnings.
[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 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 0x0500 /* For WM_CHANGEUISTATE */
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33
34 #include "wine/test.h"
35
36 #define MDI_FIRST_CHILD_ID 2004
37
38 /*
39 FIXME: add tests for these
40 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
41  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
42  WS_THICKFRAME: thick border
43  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
44  WS_BORDER (default for overlapped windows): single black border
45  none (default for child (and popup?) windows): no border
46 */
47
48 typedef enum {
49     sent=0x1,
50     posted=0x2,
51     parent=0x4,
52     wparam=0x8,
53     lparam=0x10,
54     defwinproc=0x20,
55     beginpaint=0x40,
56     optional=0x80,
57     hook=0x100
58 } msg_flags_t;
59
60 struct message {
61     UINT message;          /* the WM_* code */
62     msg_flags_t flags;     /* message props */
63     WPARAM wParam;         /* expected value of wParam */
64     LPARAM lParam;         /* expected value of lParam */
65 };
66
67 /* Empty message sequence */
68 static const struct message WmEmptySeq[] =
69 {
70     { 0 }
71 };
72 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
73 static const struct message WmCreateOverlappedSeq[] = {
74     { HCBT_CREATEWND, hook },
75     { WM_GETMINMAXINFO, sent },
76     { WM_NCCREATE, sent },
77     { WM_NCCALCSIZE, sent|wparam, 0 },
78     { WM_CREATE, sent },
79     { 0 }
80 };
81 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
82  * for a not visible overlapped window.
83  */
84 static const struct message WmSWP_ShowOverlappedSeq[] = {
85     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
86     { WM_NCPAINT, sent|wparam|optional, 1 },
87     { WM_GETTEXT, sent|defwinproc|optional },
88     { WM_ERASEBKGND, sent|optional },
89     { HCBT_ACTIVATE, hook },
90     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
91     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 }, /* Win9x: SWP_NOSENDCHANGING */
92     { WM_ACTIVATEAPP, sent|wparam, 1 },
93     { WM_NCACTIVATE, sent|wparam, 1 },
94     { WM_GETTEXT, sent|defwinproc|optional },
95     { WM_ACTIVATE, sent|wparam, 1 },
96     { HCBT_SETFOCUS, hook },
97     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
98     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
99     { WM_NCPAINT, sent|wparam|optional, 1 },
100     { WM_GETTEXT, sent|defwinproc|optional },
101     { WM_ERASEBKGND, sent|optional },
102     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
103     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
104     { WM_NCPAINT, sent|wparam|optional, 1 },
105     { WM_ERASEBKGND, sent|optional },
106     { 0 }
107 };
108 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
109  * for a visible overlapped window.
110  */
111 static const struct message WmSWP_HideOverlappedSeq[] = {
112     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
113     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
114     { 0 }
115 };
116 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
117 static const struct message WmShowOverlappedSeq[] = {
118     { WM_SHOWWINDOW, sent|wparam, 1 },
119     { WM_NCPAINT, sent|wparam|optional, 1 },
120     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
121     { WM_NCPAINT, sent|wparam|optional, 1 },
122     { WM_GETTEXT, sent|defwinproc|optional },
123     { WM_ERASEBKGND, sent|optional },
124     { HCBT_ACTIVATE, hook },
125     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
126     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
127     { WM_ACTIVATEAPP, sent|wparam, 1 },
128     { WM_NCACTIVATE, sent|wparam, 1 },
129     { WM_GETTEXT, sent|defwinproc|optional },
130     { WM_ACTIVATE, sent|wparam, 1 },
131     { HCBT_SETFOCUS, hook },
132     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
133     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
134     { WM_NCPAINT, sent|wparam|optional, 1 },
135     { WM_GETTEXT, sent|defwinproc|optional },
136     { WM_ERASEBKGND, sent|optional },
137     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
138     { WM_NCCALCSIZE, sent|optional },
139     { WM_NCPAINT, sent|optional },
140     { WM_ERASEBKGND, sent|optional },
141 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
142        * messages. Does that mean that CreateWindow doesn't set initial
143        * window dimensions for overlapped windows?
144        */
145     { WM_SIZE, sent },
146     { WM_MOVE, sent },
147 #endif
148     { 0 }
149 };
150 /* ShowWindow(SW_HIDE) for a visible overlapped window */
151 static const struct message WmHideOverlappedSeq[] = {
152     { WM_SHOWWINDOW, sent|wparam, 0 },
153     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
154     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
155     { WM_SIZE, sent },
156     { WM_MOVE, sent },
157     { WM_NCACTIVATE, sent|wparam, 0 },
158     { WM_ACTIVATE, sent|wparam, 0 },
159     { WM_ACTIVATEAPP, sent|wparam, 0 },
160     { WM_KILLFOCUS, sent|wparam, 0 },
161     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
162     { 0 }
163 };
164 /* ShowWindow(SW_HIDE) for an invisible overlapped window */
165 static const struct message WmHideInvisibleOverlappedSeq[] = {
166     { 0 }
167 };
168 /* DestroyWindow for a visible overlapped window */
169 static const struct message WmDestroyOverlappedSeq[] = {
170     { HCBT_DESTROYWND, hook },
171     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
172     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
173     { WM_NCACTIVATE, sent|wparam, 0 },
174     { WM_ACTIVATE, sent|wparam, 0 },
175     { WM_ACTIVATEAPP, sent|wparam, 0 },
176     { WM_KILLFOCUS, sent|wparam, 0 },
177     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
178     { WM_DESTROY, sent },
179     { WM_NCDESTROY, sent },
180     { 0 }
181 };
182 /* CreateWindow (for a child popup window, not initially visible) */
183 static const struct message WmCreateChildPopupSeq[] = {
184     { HCBT_CREATEWND, hook },
185     { WM_NCCREATE, sent }, 
186     { WM_NCCALCSIZE, sent|wparam, 0 },
187     { WM_CREATE, sent },
188     { WM_SIZE, sent },
189     { WM_MOVE, sent },
190     { 0 }
191 };
192 /* CreateWindow (for a popup window, not initially visible,
193  * which sets WS_VISIBLE in WM_CREATE handler)
194  */
195 static const struct message WmCreateInvisiblePopupSeq[] = {
196     { HCBT_CREATEWND, hook },
197     { WM_NCCREATE, sent }, 
198     { WM_NCCALCSIZE, sent|wparam, 0 },
199     { WM_CREATE, sent },
200     { WM_STYLECHANGING, sent },
201     { WM_STYLECHANGED, sent },
202     { WM_SIZE, sent },
203     { WM_MOVE, sent },
204     { 0 }
205 };
206 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
207  * for a popup window with WS_VISIBLE style set
208  */
209 static const struct message WmShowVisiblePopupSeq_2[] = {
210     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
211     { 0 }
212 };
213 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
214  * for a popup window with WS_VISIBLE style set
215  */
216 static const struct message WmShowVisiblePopupSeq_3[] = {
217     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
218     { HCBT_ACTIVATE, hook },
219     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
220     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
221     { WM_NCACTIVATE, sent|wparam, 1 },
222     { WM_ACTIVATE, sent|wparam, 1 },
223     { HCBT_SETFOCUS, hook },
224     { WM_KILLFOCUS, sent|parent },
225     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
226     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
227     { WM_SETFOCUS, sent|defwinproc },
228     { 0 }
229 };
230 /* CreateWindow (for child window, not initially visible) */
231 static const struct message WmCreateChildSeq[] = {
232     { HCBT_CREATEWND, hook },
233     { WM_NCCREATE, sent }, 
234     /* child is inserted into parent's child list after WM_NCCREATE returns */
235     { WM_NCCALCSIZE, sent|wparam, 0 },
236     { WM_CREATE, sent },
237     { WM_SIZE, sent },
238     { WM_MOVE, sent },
239     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
240     { 0 }
241 };
242 /* CreateWindow (for maximized child window, not initially visible) */
243 static const struct message WmCreateMaximizedChildSeq[] = {
244     { HCBT_CREATEWND, hook },
245     { WM_NCCREATE, sent }, 
246     { WM_NCCALCSIZE, sent|wparam, 0 },
247     { WM_CREATE, sent },
248     { WM_SIZE, sent },
249     { WM_MOVE, sent },
250     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
251     { WM_GETMINMAXINFO, sent },
252     { WM_WINDOWPOSCHANGING, sent },
253     { WM_NCCALCSIZE, sent|wparam, 1 },
254     { WM_WINDOWPOSCHANGED, sent },
255     { WM_SIZE, sent|defwinproc },
256     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
257     { 0 }
258 };
259 /* CreateWindow (for a child window, initially visible) */
260 static const struct message WmCreateVisibleChildSeq[] = {
261     { HCBT_CREATEWND, hook },
262     { WM_NCCREATE, sent }, 
263     /* child is inserted into parent's child list after WM_NCCREATE returns */
264     { WM_NCCALCSIZE, sent|wparam, 0 },
265     { WM_CREATE, sent },
266     { WM_SIZE, sent },
267     { WM_MOVE, sent },
268     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
269     { WM_SHOWWINDOW, sent|wparam, 1 },
270     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
271     { WM_ERASEBKGND, sent|parent|optional },
272     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
273     { 0 }
274 };
275 /* ShowWindow(SW_SHOW) for a not visible child window */
276 static const struct message WmShowChildSeq[] = {
277     { WM_SHOWWINDOW, sent|wparam, 1 },
278     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
279     { WM_ERASEBKGND, sent|parent|optional },
280     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
281     { 0 }
282 };
283 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
284  * for a not visible child window
285  */
286 static const struct message WmShowChildSeq_2[] = {
287     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
288     { WM_CHILDACTIVATE, sent },
289     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
290     { 0 }
291 };
292 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
293  * for a not visible child window
294  */
295 static const struct message WmShowChildSeq_3[] = {
296     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
297     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
298     { 0 }
299 };
300 /* DestroyWindow for a visible child window */
301 static const struct message WmDestroyChildSeq[] = {
302     { HCBT_DESTROYWND, hook },
303     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
304     { WM_SHOWWINDOW, sent|wparam, 0 },
305     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
306     { WM_ERASEBKGND, sent|parent|optional },
307     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
308     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
309     { WM_KILLFOCUS, sent },
310     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
311     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
312     { WM_SETFOCUS, sent|parent },
313     { WM_DESTROY, sent },
314     { WM_DESTROY, sent|optional }, /* a bug in win2k sp4 ? */
315     { WM_NCDESTROY, sent },
316     { WM_NCDESTROY, sent|optional }, /* a bug in win2k sp4 ? */
317     { 0 }
318 };
319 /* Moving the mouse in nonclient area */
320 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
321     { WM_NCHITTEST, sent },
322     { WM_SETCURSOR, sent },
323     { WM_NCMOUSEMOVE, posted },
324     { 0 }
325 };
326 /* Moving the mouse in client area */
327 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
328     { WM_NCHITTEST, sent },
329     { WM_SETCURSOR, sent },
330     { WM_MOUSEMOVE, posted },
331     { 0 }
332 };
333 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
334 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
335     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
336     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
337     { WM_GETMINMAXINFO, sent|defwinproc },
338     { WM_ENTERSIZEMOVE, sent|defwinproc },
339     { WM_WINDOWPOSCHANGING, sent|defwinproc },
340     { WM_WINDOWPOSCHANGED, sent|defwinproc },
341     { WM_MOVE, sent|defwinproc },
342     { WM_EXITSIZEMOVE, sent|defwinproc },
343     { 0 }
344 };
345 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
346 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
347     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
348     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
349     { WM_GETMINMAXINFO, sent|defwinproc },
350     { WM_ENTERSIZEMOVE, sent|defwinproc },
351     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
352     { WM_WINDOWPOSCHANGING, sent|defwinproc },
353     { WM_GETMINMAXINFO, sent|defwinproc },
354     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
355     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
356     { WM_GETTEXT, sent|defwinproc },
357     { WM_ERASEBKGND, sent|defwinproc },
358     { WM_WINDOWPOSCHANGED, sent|defwinproc },
359     { WM_MOVE, sent|defwinproc },
360     { WM_SIZE, sent|defwinproc },
361     { WM_EXITSIZEMOVE, sent|defwinproc },
362     { 0 }
363 };
364 /* Resizing child window with MoveWindow (32) */
365 static const struct message WmResizingChildWithMoveWindowSeq[] = {
366     { WM_WINDOWPOSCHANGING, sent },
367     { WM_NCCALCSIZE, sent|wparam, 1 },
368     { WM_ERASEBKGND, sent|optional },
369     { WM_WINDOWPOSCHANGED, sent },
370     { WM_MOVE, sent|defwinproc },
371     { WM_SIZE, sent|defwinproc },
372     { 0 }
373 };
374 /* Clicking on inactive button */
375 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
376     { WM_NCHITTEST, sent },
377     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
378     { WM_MOUSEACTIVATE, sent },
379     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
380     { WM_SETCURSOR, sent },
381     { WM_SETCURSOR, sent|parent|defwinproc },
382     { WM_LBUTTONDOWN, posted },
383     { WM_KILLFOCUS, posted|parent },
384     { WM_SETFOCUS, posted },
385     { WM_CTLCOLORBTN, posted|parent },
386     { BM_SETSTATE, posted },
387     { WM_CTLCOLORBTN, posted|parent },
388     { WM_LBUTTONUP, posted },
389     { BM_SETSTATE, posted },
390     { WM_CTLCOLORBTN, posted|parent },
391     { WM_COMMAND, posted|parent },
392     { 0 }
393 };
394 /* Reparenting a button (16/32) */
395 /* The last child (button) reparented gets topmost for its new parent. */
396 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
397     { WM_SHOWWINDOW, sent|wparam, 0 },
398     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
399     { WM_ERASEBKGND, sent|parent },
400     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
401     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
402     { WM_CHILDACTIVATE, sent },
403     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
404     { WM_MOVE, sent|defwinproc },
405     { WM_SHOWWINDOW, sent|wparam, 1 },
406     { 0 }
407 };
408 /* Creation of a custom dialog (32) */
409 static const struct message WmCreateCustomDialogSeq[] = {
410     { HCBT_CREATEWND, hook },
411     { WM_GETMINMAXINFO, sent },
412     { WM_NCCREATE, sent },
413     { WM_NCCALCSIZE, sent|wparam, 0 },
414     { WM_CREATE, sent },
415     { WM_SHOWWINDOW, sent|wparam, 1 },
416     { HCBT_ACTIVATE, hook },
417     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
418     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
419     { WM_NCACTIVATE, sent|wparam, 1 },
420     { WM_GETTEXT, sent|optional|defwinproc },
421     { WM_GETICON, sent|optional|defwinproc },
422     { WM_GETICON, sent|optional|defwinproc },
423     { WM_GETICON, sent|optional|defwinproc },
424     { WM_GETTEXT, sent|optional|defwinproc },
425     { WM_ACTIVATE, sent|wparam, 1 },
426     { WM_KILLFOCUS, sent|parent },
427     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
428     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
429     { WM_SETFOCUS, sent },
430     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
431     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
432     { WM_NCPAINT, sent|wparam, 1 },
433     { WM_GETTEXT, sent|optional|defwinproc },
434     { WM_GETICON, sent|optional|defwinproc },
435     { WM_GETICON, sent|optional|defwinproc },
436     { WM_GETICON, sent|optional|defwinproc },
437     { WM_GETTEXT, sent|optional|defwinproc },
438     { WM_ERASEBKGND, sent },
439     { WM_CTLCOLORDLG, sent|defwinproc },
440     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
441     { WM_GETTEXT, sent|optional },
442     { WM_GETICON, sent|optional },
443     { WM_GETICON, sent|optional },
444     { WM_GETICON, sent|optional },
445     { WM_GETTEXT, sent|optional },
446     { WM_NCCALCSIZE, sent|optional },
447     { WM_NCPAINT, sent|optional },
448     { WM_GETTEXT, sent|optional|defwinproc },
449     { WM_GETICON, sent|optional|defwinproc },
450     { WM_GETICON, sent|optional|defwinproc },
451     { WM_GETICON, sent|optional|defwinproc },
452     { WM_GETTEXT, sent|optional|defwinproc },
453     { WM_ERASEBKGND, sent|optional },
454     { WM_CTLCOLORDLG, sent|optional|defwinproc },
455     { WM_SIZE, sent },
456     { WM_MOVE, sent },
457     { 0 }
458 };
459 /* Calling EndDialog for a custom dialog (32) */
460 static const struct message WmEndCustomDialogSeq[] = {
461     { WM_WINDOWPOSCHANGING, sent },
462     { WM_WINDOWPOSCHANGED, sent },
463     { WM_GETTEXT, sent|optional },
464     { WM_GETICON, sent|optional },
465     { WM_GETICON, sent|optional },
466     { WM_GETICON, sent|optional },
467     { HCBT_ACTIVATE, hook },
468     { WM_NCACTIVATE, sent|wparam, 0 },
469     { WM_GETTEXT, sent|optional|defwinproc },
470     { WM_GETICON, sent|optional|defwinproc },
471     { WM_GETICON, sent|optional|defwinproc },
472     { WM_GETICON, sent|optional|defwinproc },
473     { WM_GETTEXT, sent|optional|defwinproc },
474     { WM_ACTIVATE, sent|wparam, 0 },
475     { WM_WINDOWPOSCHANGING, sent|optional },
476     { HCBT_SETFOCUS, hook },
477     { WM_KILLFOCUS, sent },
478     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
479     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
480     { WM_SETFOCUS, sent|parent|defwinproc },
481     { 0 }
482 };
483 /* Creation and destruction of a modal dialog (32) */
484 static const struct message WmModalDialogSeq[] = {
485     { WM_CANCELMODE, sent|parent },
486     { HCBT_SETFOCUS, hook },
487     { WM_KILLFOCUS, sent|parent },
488     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
489     { WM_ENABLE, sent|parent|wparam, 0 },
490     { HCBT_CREATEWND, hook },
491     { WM_SETFONT, sent },
492     { WM_INITDIALOG, sent },
493     { WM_CHANGEUISTATE, sent|optional },
494     { WM_SHOWWINDOW, sent },
495     { HCBT_ACTIVATE, hook },
496     { WM_WINDOWPOSCHANGING, sent },
497     { WM_NCACTIVATE, sent|wparam, 1 },
498     { WM_GETICON, sent|optional },
499     { WM_GETICON, sent|optional },
500     { WM_GETICON, sent|optional },
501     { WM_GETTEXT, sent|optional },
502     { WM_ACTIVATE, sent|wparam, 1 },
503     { WM_WINDOWPOSCHANGING, sent },
504     { WM_NCPAINT, sent },
505     { WM_GETICON, sent|optional },
506     { WM_GETICON, sent|optional },
507     { WM_GETICON, sent|optional },
508     { WM_GETTEXT, sent|optional },
509     { WM_ERASEBKGND, sent },
510     { WM_CTLCOLORDLG, sent },
511     { WM_WINDOWPOSCHANGED, sent },
512     { WM_GETICON, sent|optional },
513     { WM_GETICON, sent|optional },
514     { WM_GETICON, sent|optional },
515     { WM_GETTEXT, sent|optional },
516     { WM_NCCALCSIZE, sent|optional },
517     { WM_NCPAINT, sent|optional },
518     { WM_GETICON, sent|optional },
519     { WM_GETICON, sent|optional },
520     { WM_GETICON, sent|optional },
521     { WM_GETTEXT, sent|optional },
522     { WM_ERASEBKGND, sent|optional },
523     { WM_CTLCOLORDLG, sent|optional },
524     { WM_PAINT, sent|optional },
525     { WM_CTLCOLORBTN, sent },
526     { WM_ENTERIDLE, sent|parent },
527     { WM_TIMER, sent },
528     { WM_ENABLE, sent|parent|wparam, 1 },
529     { WM_WINDOWPOSCHANGING, sent },
530     { WM_WINDOWPOSCHANGED, sent },
531     { WM_GETICON, sent|optional },
532     { WM_GETICON, sent|optional },
533     { WM_GETICON, sent|optional },
534     { WM_GETTEXT, sent|optional },
535     { HCBT_ACTIVATE, hook },
536     { WM_NCACTIVATE, sent|wparam, 0 },
537     { WM_GETICON, sent|optional },
538     { WM_GETICON, sent|optional },
539     { WM_GETICON, sent|optional },
540     { WM_GETTEXT, sent|optional },
541     { WM_ACTIVATE, sent|wparam, 0 },
542     { WM_WINDOWPOSCHANGING, sent|optional },
543     { HCBT_SETFOCUS, hook },
544     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
545     { WM_SETFOCUS, sent|parent|defwinproc },
546     { HCBT_DESTROYWND, hook },
547     { WM_DESTROY, sent },
548     { WM_NCDESTROY, sent },
549     { 0 }
550 };
551 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
552 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
553     /* (inside dialog proc, handling WM_INITDIALOG) */
554     { WM_WINDOWPOSCHANGING, sent },
555     { WM_NCCALCSIZE, sent },
556     { WM_NCACTIVATE, sent|parent|wparam, 0 },
557     { WM_GETTEXT, sent|defwinproc },
558     { WM_ACTIVATE, sent|parent|wparam, 0 },
559     { WM_WINDOWPOSCHANGING, sent },
560     { WM_WINDOWPOSCHANGING, sent|parent },
561     { WM_NCACTIVATE, sent|wparam, 1 },
562     { WM_ACTIVATE, sent|wparam, 1 },
563     { WM_WINDOWPOSCHANGED, sent },
564     { WM_SIZE, sent|defwinproc },
565     /* (setting focus) */
566     { WM_SHOWWINDOW, sent|wparam, 1 },
567     { WM_WINDOWPOSCHANGING, sent },
568     { WM_NCPAINT, sent },
569     { WM_GETTEXT, sent|defwinproc },
570     { WM_ERASEBKGND, sent },
571     { WM_CTLCOLORDLG, sent|defwinproc },
572     { WM_WINDOWPOSCHANGED, sent },
573     { WM_PAINT, sent },
574     /* (bunch of WM_CTLCOLOR* for each control) */
575     { WM_PAINT, sent|parent },
576     { WM_ENTERIDLE, sent|parent|wparam, 0 },
577     { WM_SETCURSOR, sent|parent },
578     { 0 }
579 };
580 /* SetMenu for NonVisible windows with size change*/
581 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
582     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
583     { WM_NCCALCSIZE, sent|wparam, 1 },
584     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
585     { WM_MOVE, sent|defwinproc },
586     { WM_SIZE, sent|defwinproc },
587     { WM_GETICON, sent|optional },
588     { WM_GETICON, sent|optional },
589     { WM_GETICON, sent|optional },
590     { WM_GETTEXT, sent|optional },
591     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
592     { 0 }
593 };
594 /* SetMenu for NonVisible windows with no size change */
595 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
596     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
597     { WM_NCCALCSIZE, sent|wparam, 1 },
598     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
599     { 0 }
600 };
601 /* SetMenu for Visible windows with size change */
602 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
603     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
604     { WM_NCCALCSIZE, sent|wparam, 1 },
605     { WM_NCPAINT, sent|wparam, 1 },
606     { WM_GETTEXT, sent|defwinproc|optional },
607     { WM_ERASEBKGND, sent|optional },
608     { WM_ACTIVATE, sent|optional },
609     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
610     { WM_MOVE, sent|defwinproc },
611     { WM_SIZE, sent|defwinproc },
612     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
613     { WM_NCPAINT, sent|wparam|optional, 1 },
614     { WM_ERASEBKGND, sent|optional },
615     { 0 }
616 };
617 /* SetMenu for Visible windows with no size change */
618 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
619     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
620     { WM_NCCALCSIZE, sent|wparam, 1 },
621     { WM_NCPAINT, sent|wparam, 1 },
622     { WM_GETTEXT, sent|defwinproc|optional },
623     { WM_ERASEBKGND, sent|optional },
624     { WM_ACTIVATE, sent|optional },
625     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
626     { 0 }
627 };
628 /* DrawMenuBar for a visible window */
629 static const struct message WmDrawMenuBarSeq[] =
630 {
631     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
632     { WM_NCCALCSIZE, sent|wparam, 1 },
633     { WM_NCPAINT, sent|wparam, 1 },
634     { WM_GETTEXT, sent|defwinproc|optional },
635     { WM_ERASEBKGND, sent|optional },
636     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
637     { 0 }
638 };
639
640 static const struct message WmSetRedrawFalseSeq[] =
641 {
642     { WM_SETREDRAW, sent|wparam, 0 },
643     { 0 }
644 };
645
646 static const struct message WmSetRedrawTrueSeq[] =
647 {
648     { WM_SETREDRAW, sent|wparam, 1 },
649     { 0 }
650 };
651
652 static const struct message WmEnableWindowSeq[] =
653 {
654     { WM_CANCELMODE, sent },
655     { WM_ENABLE, sent },
656     { 0 }
657 };
658
659 static const struct message WmGetScrollRangeSeq[] =
660 {
661     { SBM_GETRANGE, sent },
662     { 0 }
663 };
664 static const struct message WmGetScrollInfoSeq[] =
665 {
666     { SBM_GETSCROLLINFO, sent },
667     { 0 }
668 };
669 static const struct message WmSetScrollRangeSeq[] =
670 {
671     /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
672        sends SBM_SETSCROLLINFO.
673      */
674     { SBM_SETSCROLLINFO, sent },
675     { 0 }
676 };
677 /* SetScrollRange for a window without a non-client area */
678 static const struct message WmSetScrollRangeHVSeq[] =
679 {
680     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
681     { WM_NCCALCSIZE, sent|wparam, 1 },
682     { WM_GETTEXT, sent|defwinproc|optional },
683     { WM_ERASEBKGND, sent|optional },
684     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
685     { 0 }
686 };
687 /* SetScrollRange for a window with a non-client area */
688 static const struct message WmSetScrollRangeHV_NC_Seq[] =
689 {
690     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
691     { WM_NCCALCSIZE, sent|wparam, 1 },
692     { WM_NCPAINT, sent|optional },
693     { WM_GETTEXT, sent|defwinproc|optional },
694     { WM_ERASEBKGND, sent|optional },
695     { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
696     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
697     { WM_SIZE, sent|defwinproc },
698     { 0 }
699 };
700
701 static int after_end_dialog;
702 static int sequence_cnt, sequence_size;
703 static struct message* sequence;
704
705 static void add_message(const struct message *msg)
706 {
707     if (!sequence) 
708     {
709         sequence_size = 10;
710         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
711     }
712     if (sequence_cnt == sequence_size) 
713     {
714         sequence_size *= 2;
715         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
716     }
717     assert(sequence);
718
719     sequence[sequence_cnt].message = msg->message;
720     sequence[sequence_cnt].flags = msg->flags;
721     sequence[sequence_cnt].wParam = msg->wParam;
722     sequence[sequence_cnt].lParam = msg->lParam;
723
724     sequence_cnt++;
725 }
726
727 static void flush_sequence()
728 {
729     HeapFree(GetProcessHeap(), 0, sequence);
730     sequence = 0;
731     sequence_cnt = sequence_size = 0;
732 }
733
734 static void ok_sequence(const struct message *expected, const char *context, int todo)
735 {
736     static const struct message end_of_sequence = { 0, 0, 0, 0 };
737     const struct message *actual;
738     
739     add_message(&end_of_sequence);
740
741     actual = sequence;
742
743     while (expected->message && actual->message)
744     {
745         trace("expected %04x - actual %04x\n", expected->message, actual->message);
746
747         if (expected->message == actual->message)
748         {
749             if (expected->flags & wparam)
750                  ok (expected->wParam == actual->wParam,
751                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
752                      context, expected->message, expected->wParam, actual->wParam);
753             if (expected->flags & lparam)
754                  ok (expected->lParam == actual->lParam,
755                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
756                      context, expected->message, expected->lParam, actual->lParam);
757             ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
758                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
759                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
760             ok ((expected->flags & beginpaint) == (actual->flags & beginpaint),
761                 "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
762                 context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
763             ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
764                 "%s: the msg 0x%04x should have been %s\n",
765                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
766             ok ((expected->flags & parent) == (actual->flags & parent),
767                 "%s: the msg 0x%04x was expected in %s\n",
768                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
769             ok ((expected->flags & hook) == (actual->flags & hook),
770                 "%s: the msg 0x%04x should have been sent by a hook\n",
771                 context, expected->message);
772             expected++;
773             actual++;
774         }
775         else if (expected->flags & optional)
776             expected++;
777         else if (todo)
778         {
779             todo_wine {
780                 ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
781                     context, expected->message, actual->message);
782                 expected++;
783                 actual++;
784             }
785         }
786         else
787         {
788             ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
789                 context, expected->message, actual->message);
790             expected++;
791             actual++;
792         }
793     }
794
795     /* skip all optional trailing messages */
796     while (expected->message && (expected->flags & optional))
797         expected++;
798
799     if (todo)
800     {
801         todo_wine {
802             if (expected->message || actual->message)
803                 ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
804                     context, expected->message, actual->message);
805         }
806     }
807     else
808     {
809         if (expected->message || actual->message)
810             ok (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
811                 context, expected->message, actual->message);
812     }
813
814     flush_sequence();
815 }
816
817 /******************************** MDI test **********************************/
818
819 /* CreateWindow for MDI frame window, initially visible */
820 static const struct message WmCreateMDIframeSeq[] = {
821     { HCBT_CREATEWND, hook },
822     { WM_GETMINMAXINFO, sent },
823     { WM_NCCREATE, sent },
824     { WM_NCCALCSIZE, sent|wparam, 0 },
825     { WM_CREATE, sent },
826     { WM_SHOWWINDOW, sent|wparam, 1 },
827     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
828     { HCBT_ACTIVATE, hook },
829     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
830     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
831     { WM_WINDOWPOSCHANGED, sent|wparam|optional, 0 }, /* Win9x */
832     { WM_ACTIVATEAPP, sent|wparam, 1 },
833     { WM_NCACTIVATE, sent|wparam, 1 },
834     { WM_ACTIVATE, sent|wparam, 1 },
835     { HCBT_SETFOCUS, hook },
836     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
837     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
838     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
839     { WM_SIZE, sent },
840     { WM_MOVE, sent },
841     { 0 }
842 };
843 /* DestroyWindow for MDI frame window, initially visible */
844 static const struct message WmDestroyMDIframeSeq[] = {
845     { HCBT_DESTROYWND, hook },
846     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
847     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
848     { WM_NCACTIVATE, sent|wparam, 0 },
849     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
850     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
851     { WM_DESTROY, sent },
852     { WM_NCDESTROY, sent },
853     { 0 }
854 };
855 /* CreateWindow for MDI client window, initially visible */
856 static const struct message WmCreateMDIclientSeq[] = {
857     { HCBT_CREATEWND, hook },
858     { WM_NCCREATE, sent },
859     { WM_NCCALCSIZE, sent|wparam, 0 },
860     { WM_CREATE, sent },
861     { WM_SIZE, sent },
862     { WM_MOVE, sent },
863     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
864     { WM_SHOWWINDOW, sent|wparam, 1 },
865     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
866     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
867     { 0 }
868 };
869 /* DestroyWindow for MDI client window, initially visible */
870 static const struct message WmDestroyMDIclientSeq[] = {
871     { HCBT_DESTROYWND, hook },
872     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
873     { WM_SHOWWINDOW, sent|wparam, 0 },
874     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
875     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
876     { WM_DESTROY, sent },
877     { WM_NCDESTROY, sent },
878     { 0 }
879 };
880 /* CreateWindow for MDI child window, initially visible */
881 static const struct message WmCreateMDIchildVisibleSeq[] = {
882     { HCBT_CREATEWND, hook },
883     { WM_NCCREATE, sent }, 
884     { WM_NCCALCSIZE, sent|wparam, 0 },
885     { WM_CREATE, sent },
886     { WM_SIZE, sent },
887     { WM_MOVE, sent },
888     /* Win2k sends wparam set to
889      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
890      * while Win9x doesn't bother to set child window id according to
891      * CLIENTCREATESTRUCT.idFirstChild
892      */
893     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
894     { WM_SHOWWINDOW, sent|wparam, 1 },
895     { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, /*SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER*/
896     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
897     { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
898     { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, /*SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE*/
899     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
900     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 }, /*SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/
901
902     /* Win9x: message sequence terminates here. */
903
904     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
905     { HCBT_SETFOCUS, hook }, /* in MDI client */
906     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
907     { WM_SETFOCUS, sent }, /* in MDI client */
908     { HCBT_SETFOCUS, hook },
909     { WM_KILLFOCUS, sent }, /* in MDI client */
910     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
911     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
912     { WM_SETFOCUS, sent|defwinproc },
913     { WM_MDIACTIVATE, sent|defwinproc },
914     { 0 }
915 };
916 /* DestroyWindow for MDI child window, initially visible */
917 static const struct message WmDestroyMDIchildVisibleSeq[] = {
918     { HCBT_DESTROYWND, hook },
919     /* Win2k sends wparam set to
920      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
921      * while Win9x doesn't bother to set child window id according to
922      * CLIENTCREATESTRUCT.idFirstChild
923      */
924     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
925     { WM_SHOWWINDOW, sent|wparam, 0 },
926     { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, /*SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER*/
927     { WM_ERASEBKGND, sent|parent|optional },
928     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
929
930     /* { WM_DESTROY, sent }
931      * Win9x: message sequence terminates here.
932      */
933
934     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
935     { WM_KILLFOCUS, sent },
936     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
937     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
938     { WM_SETFOCUS, sent }, /* in MDI client */
939
940     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
941     { WM_KILLFOCUS, sent }, /* in MDI client */
942     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
943     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
944     { WM_SETFOCUS, sent }, /* in MDI client */
945
946     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
947     { WM_KILLFOCUS, sent },
948     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
949     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
950     { WM_SETFOCUS, sent }, /* in MDI client */
951
952     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
953     { WM_KILLFOCUS, sent }, /* in MDI client */
954     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
955     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
956     { WM_SETFOCUS, sent }, /* in MDI client */
957
958     { WM_DESTROY, sent },
959
960     { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
961     { WM_KILLFOCUS, sent },
962     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
963     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
964     { WM_SETFOCUS, sent }, /* in MDI client */
965
966     { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
967     { WM_KILLFOCUS, sent }, /* in MDI client */
968     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
969     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
970     { WM_SETFOCUS, sent }, /* in MDI client */
971
972     { WM_NCDESTROY, sent },
973     { 0 }
974 };
975 /* CreateWindow for MDI child window, initially invisible */
976 static const struct message WmCreateMDIchildInvisibleSeq[] = {
977     { HCBT_CREATEWND, hook },
978     { WM_NCCREATE, sent }, 
979     { WM_NCCALCSIZE, sent|wparam, 0 },
980     { WM_CREATE, sent },
981     { WM_SIZE, sent },
982     { WM_MOVE, sent },
983     /* Win2k sends wparam set to
984      * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
985      * while Win9x doesn't bother to set child window id according to
986      * CLIENTCREATESTRUCT.idFirstChild
987      */
988     { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
989     { 0 }
990 };
991 /* DestroyWindow for MDI child window, initially invisible */
992 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
993     { HCBT_DESTROYWND, hook },
994     /* Win2k sends wparam set to
995      * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
996      * while Win9x doesn't bother to set child window id according to
997      * CLIENTCREATESTRUCT.idFirstChild
998      */
999     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
1000     { WM_DESTROY, sent },
1001     { WM_NCDESTROY, sent },
1002     { 0 }
1003 };
1004
1005 static HWND mdi_client;
1006 static WNDPROC old_mdi_client_proc;
1007
1008 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1009 {
1010     struct message msg;
1011
1012     /* do not log painting messages */
1013     if (message != WM_PAINT &&
1014         message != WM_ERASEBKGND &&
1015         message != WM_NCPAINT &&
1016         message != WM_GETTEXT)
1017     {
1018         trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1019
1020         msg.message = message;
1021         msg.flags = sent|wparam|lparam;
1022         msg.wParam = wParam;
1023         msg.lParam = lParam;
1024         add_message(&msg);
1025     }
1026
1027     return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
1028 }
1029
1030 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1031 {
1032     static long defwndproc_counter = 0;
1033     LRESULT ret;
1034     struct message msg;
1035
1036     /* do not log painting messages */
1037     if (message != WM_PAINT &&
1038         message != WM_ERASEBKGND &&
1039         message != WM_NCPAINT &&
1040         message != WM_GETTEXT)
1041     {
1042         trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1043
1044         switch (message)
1045         {
1046             case WM_WINDOWPOSCHANGING:
1047             case WM_WINDOWPOSCHANGED:
1048             {
1049                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
1050
1051                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1052                 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1053                       winpos->hwnd, winpos->hwndInsertAfter,
1054                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1055                 break;
1056             }
1057         }
1058
1059         msg.message = message;
1060         msg.flags = sent|wparam|lparam;
1061         if (defwndproc_counter) msg.flags |= defwinproc;
1062         msg.wParam = wParam;
1063         msg.lParam = lParam;
1064         add_message(&msg);
1065     }
1066
1067     defwndproc_counter++;
1068     ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
1069     defwndproc_counter--;
1070
1071     return ret;
1072 }
1073
1074 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1075 {
1076     static long defwndproc_counter = 0;
1077     LRESULT ret;
1078     struct message msg;
1079
1080     /* do not log painting messages */
1081     if (message != WM_PAINT &&
1082         message != WM_ERASEBKGND &&
1083         message != WM_NCPAINT &&
1084         message != WM_GETTEXT)
1085     {
1086         trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1087
1088         msg.message = message;
1089         msg.flags = sent|wparam|lparam;
1090         if (defwndproc_counter) msg.flags |= defwinproc;
1091         msg.wParam = wParam;
1092         msg.lParam = lParam;
1093         add_message(&msg);
1094     }
1095
1096     defwndproc_counter++;
1097     ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
1098     defwndproc_counter--;
1099
1100     return ret;
1101 }
1102
1103 static BOOL mdi_RegisterWindowClasses(void)
1104 {
1105     WNDCLASSA cls;
1106
1107     cls.style = 0;
1108     cls.lpfnWndProc = mdi_frame_wnd_proc;
1109     cls.cbClsExtra = 0;
1110     cls.cbWndExtra = 0;
1111     cls.hInstance = GetModuleHandleA(0);
1112     cls.hIcon = 0;
1113     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1114     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1115     cls.lpszMenuName = NULL;
1116     cls.lpszClassName = "MDI_frame_class";
1117     if (!RegisterClassA(&cls)) return FALSE;
1118
1119     cls.lpfnWndProc = mdi_child_wnd_proc;
1120     cls.lpszClassName = "MDI_child_class";
1121     if (!RegisterClassA(&cls)) return FALSE;
1122
1123     if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
1124     old_mdi_client_proc = cls.lpfnWndProc;
1125     cls.hInstance = GetModuleHandleA(0);
1126     cls.lpfnWndProc = mdi_client_hook_proc;
1127     cls.lpszClassName = "MDI_client_class";
1128     if (!RegisterClassA(&cls)) assert(0);
1129
1130     return TRUE;
1131 }
1132
1133 static void test_mdi_messages(void)
1134 {
1135     CLIENTCREATESTRUCT client_cs;
1136     HWND mdi_frame, mdi_child;
1137
1138     assert(mdi_RegisterWindowClasses());
1139
1140     flush_sequence();
1141
1142     trace("creating MDI frame window\n");
1143     mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
1144                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1145                                 WS_MAXIMIZEBOX | WS_VISIBLE,
1146                                 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1147                                 GetDesktopWindow(), 0,
1148                                 GetModuleHandleA(0), NULL);
1149     assert(mdi_frame);
1150     ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
1151
1152     trace("creating MDI client window\n");
1153     client_cs.hWindowMenu = 0;
1154     client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
1155     mdi_client = CreateWindowExA(0, "MDI_client_class",
1156                                  NULL,
1157                                  WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
1158                                  0, 0, 0, 0,
1159                                  mdi_frame, 0, GetModuleHandleA(0), &client_cs);
1160     assert(mdi_client);
1161     ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", TRUE);
1162
1163     ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
1164
1165     SetFocus(0);
1166     flush_sequence();
1167
1168     trace("creating visible MDI child window\n");
1169     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1170                                 WS_CHILD | WS_VISIBLE,
1171                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1172                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1173     assert(mdi_child);
1174     ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", TRUE);
1175
1176     ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
1177     ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
1178
1179     DestroyWindow(mdi_child);
1180     ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
1181
1182     SetFocus(0);
1183     flush_sequence();
1184
1185     trace("creating invisible MDI child window\n");
1186     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
1187                                 WS_CHILD,
1188                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
1189                                 mdi_client, 0, GetModuleHandleA(0), NULL);
1190     assert(mdi_child);
1191     ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", TRUE);
1192
1193     ok(!(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
1194     ok(!IsWindowVisible(mdi_child), "MDI child should not be visible\n");
1195
1196     DestroyWindow(mdi_child);
1197     ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", TRUE);
1198
1199     DestroyWindow(mdi_client);
1200     ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
1201
1202     DestroyWindow(mdi_frame);
1203     ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
1204 }
1205 /************************* End of MDI test **********************************/
1206
1207 static void test_WM_SETREDRAW(HWND hwnd)
1208 {
1209     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
1210
1211     flush_sequence();
1212
1213     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
1214     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
1215
1216     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
1217     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
1218
1219     flush_sequence();
1220     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
1221     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
1222
1223     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1224     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
1225
1226     /* restore original WS_VISIBLE state */
1227     SetWindowLongA(hwnd, GWL_STYLE, style);
1228
1229     flush_sequence();
1230 }
1231
1232 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1233 {
1234     struct message msg;
1235
1236     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1237
1238     msg.message = message;
1239     msg.flags = sent|wparam|lparam;
1240     msg.wParam = wParam;
1241     msg.lParam = lParam;
1242     add_message(&msg);
1243
1244     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
1245     if (message == WM_TIMER) EndDialog( hwnd, 0 );
1246     return 0;
1247 }
1248
1249 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1250 {
1251     DWORD style, exstyle;
1252     INT xmin, xmax;
1253
1254     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1255     style = GetWindowLongA(hwnd, GWL_STYLE);
1256     /* do not be confused by WS_DLGFRAME set */
1257     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1258
1259     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1260     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1261
1262     ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1263     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1264         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
1265     else
1266         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", TRUE);
1267
1268     style = GetWindowLongA(hwnd, GWL_STYLE);
1269     if (set) ok(style & set, "style %08lx should be set\n", set);
1270     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1271
1272     /* a subsequent call should do nothing */
1273     ok(SetScrollRange(hwnd, ctl, min, max, FALSE), "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
1274     ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1275
1276     xmin = 0xdeadbeef;
1277     xmax = 0xdeadbeef;
1278     trace("Ignore GetScrollRange error below if you are on Win9x\n");
1279     ok(GetScrollRange(hwnd, ctl, &xmin, &xmax), "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
1280     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1281     ok(xmin == min, "unexpected min scroll value %d\n", xmin);
1282     ok(xmax == max, "unexpected max scroll value %d\n", xmax);
1283 }
1284
1285 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
1286 {
1287     DWORD style, exstyle;
1288     SCROLLINFO si;
1289
1290     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1291     style = GetWindowLongA(hwnd, GWL_STYLE);
1292     /* do not be confused by WS_DLGFRAME set */
1293     if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
1294
1295     if (clear) ok(style & clear, "style %08lx should be set\n", clear);
1296     if (set) ok(!(style & set), "style %08lx should not be set\n", set);
1297
1298     si.cbSize = sizeof(si);
1299     si.fMask = SIF_RANGE;
1300     si.nMin = min;
1301     si.nMax = max;
1302     SetScrollInfo(hwnd, ctl, &si, TRUE);
1303     if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
1304         ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
1305     else
1306         ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", TRUE);
1307
1308     style = GetWindowLongA(hwnd, GWL_STYLE);
1309     if (set) ok(style & set, "style %08lx should be set\n", set);
1310     if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
1311
1312     /* a subsequent call should do nothing */
1313     SetScrollInfo(hwnd, ctl, &si, TRUE);
1314     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1315
1316     si.fMask = SIF_PAGE;
1317     si.nPage = 5;
1318     SetScrollInfo(hwnd, ctl, &si, FALSE);
1319     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1320
1321     si.fMask = SIF_POS;
1322     si.nPos = max - 1;
1323     SetScrollInfo(hwnd, ctl, &si, FALSE);
1324     ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
1325
1326     si.fMask = SIF_RANGE;
1327     si.nMin = 0xdeadbeef;
1328     si.nMax = 0xdeadbeef;
1329     ok(GetScrollInfo(hwnd, ctl, &si), "GetScrollInfo error %ld\n", GetLastError());
1330     ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT)", FALSE);
1331     ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
1332     ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
1333 }
1334
1335 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
1336 static void test_scroll_messages(HWND hwnd)
1337 {
1338     SCROLLINFO si;
1339     INT min, max;
1340
1341     min = 0xdeadbeef;
1342     max = 0xdeadbeef;
1343     ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1344     if (sequence->message != WmGetScrollRangeSeq[0].message)
1345         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1346     /* values of min and max are undefined */
1347     flush_sequence();
1348
1349     ok(SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE), "SetScrollRange error %ld\n", GetLastError());
1350     if (sequence->message != WmSetScrollRangeSeq[0].message)
1351         trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1352     flush_sequence();
1353
1354     min = 0xdeadbeef;
1355     max = 0xdeadbeef;
1356     ok(GetScrollRange(hwnd, SB_CTL, &min, &max), "GetScrollRange error %ld\n", GetLastError());
1357     if (sequence->message != WmGetScrollRangeSeq[0].message)
1358         trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
1359     /* values of min and max are undefined */
1360     flush_sequence();
1361
1362     si.cbSize = sizeof(si);
1363     si.fMask = SIF_RANGE;
1364     si.nMin = 20;
1365     si.nMax = 160;
1366     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
1367     if (sequence->message != WmSetScrollRangeSeq[0].message)
1368         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1369     flush_sequence();
1370
1371     si.fMask = SIF_PAGE;
1372     si.nPage = 10;
1373     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
1374     if (sequence->message != WmSetScrollRangeSeq[0].message)
1375         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1376     flush_sequence();
1377
1378     si.fMask = SIF_POS;
1379     si.nPos = 20;
1380     SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
1381     if (sequence->message != WmSetScrollRangeSeq[0].message)
1382         trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1383     flush_sequence();
1384
1385     si.fMask = SIF_RANGE;
1386     si.nMin = 0xdeadbeef;
1387     si.nMax = 0xdeadbeef;
1388     ok(GetScrollInfo(hwnd, SB_CTL, &si), "GetScrollInfo error %ld\n", GetLastError());
1389     if (sequence->message != WmGetScrollInfoSeq[0].message)
1390         trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
1391     /* values of min and max are undefined */
1392     flush_sequence();
1393
1394     /* set WS_HSCROLL */
1395     test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
1396     /* clear WS_HSCROLL */
1397     test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
1398
1399     /* set WS_HSCROLL */
1400     test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
1401     /* clear WS_HSCROLL */
1402     test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
1403
1404     /* set WS_VSCROLL */
1405     test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
1406     /* clear WS_VSCROLL */
1407     test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
1408
1409     /* set WS_VSCROLL */
1410     test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
1411     /* clear WS_VSCROLL */
1412     test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
1413 }
1414
1415 /* test if we receive the right sequence of messages */
1416 static void test_messages(void)
1417 {
1418     HWND hwnd, hparent, hchild;
1419     HWND hchild2, hbutton;
1420     HMENU hmenu;
1421
1422     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
1423                            100, 100, 200, 200, 0, 0, 0, NULL);
1424     ok (hwnd != 0, "Failed to create overlapped window\n");
1425     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
1426
1427     /* test ShowWindow(SW_HIDE) on a newly created invisible window */
1428     ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
1429     ok_sequence(WmHideInvisibleOverlappedSeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
1430
1431     /* test WM_SETREDRAW on a not visible top level window */
1432     test_WM_SETREDRAW(hwnd);
1433
1434     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1435     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
1436     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
1437
1438     ok(GetActiveWindow() == hwnd, "window should be active\n");
1439     ok(GetFocus() == hwnd, "window should have input focus\n");
1440     ShowWindow(hwnd, SW_HIDE);
1441     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
1442     
1443     ShowWindow(hwnd, SW_SHOW);
1444     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
1445
1446     ok(GetActiveWindow() == hwnd, "window should be active\n");
1447     ok(GetFocus() == hwnd, "window should have input focus\n");
1448     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1449     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
1450     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
1451
1452     /* test WM_SETREDRAW on a visible top level window */
1453     ShowWindow(hwnd, SW_SHOW);
1454     test_WM_SETREDRAW(hwnd);
1455
1456     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
1457     test_scroll_messages(hwnd);
1458
1459     DestroyWindow(hwnd);
1460     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
1461
1462     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1463                               100, 100, 200, 200, 0, 0, 0, NULL);
1464     ok (hparent != 0, "Failed to create parent window\n");
1465     flush_sequence();
1466
1467     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
1468                              0, 0, 10, 10, hparent, 0, 0, NULL);
1469     ok (hchild != 0, "Failed to create child window\n");
1470     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
1471     DestroyWindow(hchild);
1472     flush_sequence();
1473
1474     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
1475                              0, 0, 10, 10, hparent, 0, 0, NULL);
1476     ok (hchild != 0, "Failed to create child window\n");
1477     ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
1478
1479     trace("testing scroll APIs on a visible child window %p\n", hchild);
1480     test_scroll_messages(hchild);
1481
1482     DestroyWindow(hchild);
1483     flush_sequence();
1484
1485     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
1486                              0, 0, 10, 10, hparent, 0, 0, NULL);
1487     ok (hchild != 0, "Failed to create child window\n");
1488     ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
1489     
1490     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
1491                                100, 100, 50, 50, hparent, 0, 0, NULL);
1492     ok (hchild2 != 0, "Failed to create child2 window\n");
1493     flush_sequence();
1494
1495     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
1496                               0, 100, 50, 50, hchild, 0, 0, NULL);
1497     ok (hbutton != 0, "Failed to create button window\n");
1498
1499     /* test WM_SETREDRAW on a not visible child window */
1500     test_WM_SETREDRAW(hchild);
1501
1502     ShowWindow(hchild, SW_SHOW);
1503     ok_sequence(WmShowChildSeq, "ShowWindow:child", FALSE);
1504
1505     /* test WM_SETREDRAW on a visible child window */
1506     test_WM_SETREDRAW(hchild);
1507
1508     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
1509     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
1510
1511     ShowWindow(hchild, SW_HIDE);
1512     flush_sequence();
1513     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1514     ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
1515
1516     ShowWindow(hchild, SW_HIDE);
1517     flush_sequence();
1518     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
1519     ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
1520
1521     /* DestroyWindow sequence below expects that a child has focus */
1522     SetFocus(hchild);
1523     flush_sequence();
1524
1525     DestroyWindow(hchild);
1526     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
1527     DestroyWindow(hchild2);
1528     DestroyWindow(hbutton);
1529
1530     flush_sequence();
1531     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
1532                              0, 0, 100, 100, hparent, 0, 0, NULL);
1533     ok (hchild != 0, "Failed to create child popup window\n");
1534     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
1535     DestroyWindow(hchild);
1536
1537     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
1538     flush_sequence();
1539     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
1540                              0, 0, 100, 100, hparent, 0, 0, NULL);
1541     ok (hchild != 0, "Failed to create popup window\n");
1542     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
1543     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1544     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
1545     flush_sequence();
1546     ShowWindow(hchild, SW_SHOW);
1547     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
1548     flush_sequence();
1549     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1550     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
1551     flush_sequence();
1552     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
1553     ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
1554     DestroyWindow(hchild);
1555
1556     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
1557      * changes nothing in message sequences.
1558      */
1559     flush_sequence();
1560     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
1561                              0, 0, 100, 100, hparent, 0, 0, NULL);
1562     ok (hchild != 0, "Failed to create popup window\n");
1563     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
1564     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
1565     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
1566     flush_sequence();
1567     ShowWindow(hchild, SW_SHOW);
1568     ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
1569     flush_sequence();
1570     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1571     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
1572     DestroyWindow(hchild);
1573
1574     flush_sequence();
1575     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
1576                            0, 0, 100, 100, hparent, 0, 0, NULL);
1577     ok(hwnd != 0, "Failed to create custom dialog window\n");
1578     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
1579
1580     trace("testing scroll APIs on a visible dialog %p\n", hwnd);
1581     test_scroll_messages(hwnd);
1582
1583     flush_sequence();
1584     after_end_dialog = 1;
1585     EndDialog( hwnd, 0 );
1586     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
1587
1588     DestroyWindow(hwnd);
1589     after_end_dialog = 0;
1590
1591     flush_sequence();
1592     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
1593     ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
1594
1595     DestroyWindow(hparent);
1596     flush_sequence();
1597
1598     /* Message sequence for SetMenu */
1599     hmenu = CreateMenu();
1600     ok (hmenu != 0, "Failed to create menu\n");
1601     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
1602     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
1603                            100, 100, 200, 200, 0, hmenu, 0, NULL);
1604     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
1605     ok (SetMenu(hwnd, 0), "SetMenu\n");
1606     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
1607     ok (SetMenu(hwnd, 0), "SetMenu\n");
1608     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
1609     ShowWindow(hwnd, SW_SHOW);
1610     flush_sequence();
1611     ok (SetMenu(hwnd, 0), "SetMenu\n");
1612     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
1613     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
1614     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
1615
1616     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
1617     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
1618
1619     DestroyWindow(hwnd);
1620     flush_sequence();
1621
1622     /* Message sequence for EnableWindow */
1623     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1624                               100, 100, 200, 200, 0, 0, 0, NULL);
1625     ok (hparent != 0, "Failed to create parent window\n");
1626     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
1627                              0, 0, 10, 10, hparent, 0, 0, NULL);
1628     ok (hchild != 0, "Failed to create child window\n");
1629
1630     SetFocus(hchild);
1631     flush_sequence();
1632
1633     EnableWindow(hparent, FALSE);
1634     ok_sequence(WmEnableWindowSeq, "EnableWindow", FALSE);
1635
1636     DestroyWindow(hparent);
1637     flush_sequence();
1638 }
1639
1640 /****************** button message test *************************/
1641 static const struct message WmSetFocusButtonSeq[] =
1642 {
1643     { HCBT_SETFOCUS, hook },
1644     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1645     { WM_SETFOCUS, sent|wparam, 0 },
1646     { WM_CTLCOLORBTN, sent|defwinproc },
1647     { 0 }
1648 };
1649 static const struct message WmKillFocusButtonSeq[] =
1650 {
1651     { HCBT_SETFOCUS, hook },
1652     { WM_KILLFOCUS, sent|wparam, 0 },
1653     { WM_CTLCOLORBTN, sent|defwinproc },
1654     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1655     { 0 }
1656 };
1657 static const struct message WmSetFocusStaticSeq[] =
1658 {
1659     { HCBT_SETFOCUS, hook },
1660     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1661     { WM_SETFOCUS, sent|wparam, 0 },
1662     { WM_CTLCOLORSTATIC, sent|defwinproc },
1663     { 0 }
1664 };
1665 static const struct message WmKillFocusStaticSeq[] =
1666 {
1667     { HCBT_SETFOCUS, hook },
1668     { WM_KILLFOCUS, sent|wparam, 0 },
1669     { WM_CTLCOLORSTATIC, sent|defwinproc },
1670     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1671     { 0 }
1672 };
1673 static const struct message WmLButtonDownSeq[] =
1674 {
1675     { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
1676     { HCBT_SETFOCUS, hook },
1677     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1678     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
1679     { WM_CTLCOLORBTN, sent|defwinproc },
1680     { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
1681     { WM_CTLCOLORBTN, sent|defwinproc },
1682     { 0 }
1683 };
1684 static const struct message WmLButtonUpSeq[] =
1685 {
1686     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
1687     { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
1688     { WM_CTLCOLORBTN, sent|defwinproc },
1689     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
1690     { 0 }
1691 };
1692
1693 static WNDPROC old_button_proc;
1694
1695 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1696 {
1697     static long defwndproc_counter = 0;
1698     LRESULT ret;
1699     struct message msg;
1700
1701     trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1702
1703     msg.message = message;
1704     msg.flags = sent|wparam|lparam;
1705     if (defwndproc_counter) msg.flags |= defwinproc;
1706     msg.wParam = wParam;
1707     msg.lParam = lParam;
1708     add_message(&msg);
1709
1710     if (message == BM_SETSTATE)
1711         ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
1712
1713     defwndproc_counter++;
1714     ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
1715     defwndproc_counter--;
1716
1717     return ret;
1718 }
1719
1720 static void subclass_button(void)
1721 {
1722     WNDCLASSA cls;
1723
1724     if (!GetClassInfoA(0, "button", &cls)) assert(0);
1725
1726     old_button_proc = cls.lpfnWndProc;
1727
1728     cls.hInstance = GetModuleHandle(0);
1729     cls.lpfnWndProc = button_hook_proc;
1730     cls.lpszClassName = "my_button_class";
1731     if (!RegisterClassA(&cls)) assert(0);
1732 }
1733
1734 static void test_button_messages(void)
1735 {
1736     static const struct
1737     {
1738         DWORD style;
1739         const struct message *setfocus;
1740         const struct message *killfocus;
1741     } button[] = {
1742         { BS_PUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
1743         { BS_DEFPUSHBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
1744         { BS_CHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1745         { BS_AUTOCHECKBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1746         { BS_RADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1747         { BS_3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1748         { BS_AUTO3STATE, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1749         { BS_GROUPBOX, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1750         { BS_USERBUTTON, WmSetFocusButtonSeq, WmKillFocusButtonSeq },
1751         { BS_AUTORADIOBUTTON, WmSetFocusStaticSeq, WmKillFocusStaticSeq },
1752         { BS_OWNERDRAW, WmSetFocusButtonSeq, WmKillFocusButtonSeq }
1753     };
1754     int i;
1755     HWND hwnd;
1756
1757     subclass_button();
1758
1759     for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
1760     {
1761         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
1762                                0, 0, 50, 14, 0, 0, 0, NULL);
1763         ok(hwnd != 0, "Failed to create button window\n");
1764
1765         ShowWindow(hwnd, SW_SHOW);
1766         UpdateWindow(hwnd);
1767         SetFocus(0);
1768         flush_sequence();
1769
1770         trace("button style %08lx\n", button[i].style);
1771         SetFocus(hwnd);
1772         ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
1773
1774         SetFocus(0);
1775         ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
1776
1777         DestroyWindow(hwnd);
1778     }
1779
1780     hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
1781                            0, 0, 50, 14, 0, 0, 0, NULL);
1782     ok(hwnd != 0, "Failed to create button window\n");
1783
1784     SetFocus(0);
1785     flush_sequence();
1786
1787     SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
1788     ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
1789
1790     SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
1791     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONDOWN on a button", FALSE);
1792     DestroyWindow(hwnd);
1793 }
1794
1795 /************* painting message test ********************/
1796
1797 static void dump_region(HRGN hrgn)
1798 {
1799     DWORD i, size;
1800     RGNDATA *data = NULL;
1801     RECT *rect;
1802
1803     if (!hrgn)
1804     {
1805         printf( "null region\n" );
1806         return;
1807     }
1808     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
1809     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
1810     GetRegionData( hrgn, size, data );
1811     printf("%ld rects:", data->rdh.nCount );
1812     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
1813         printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
1814     printf("\n");
1815     HeapFree( GetProcessHeap(), 0, data );
1816 }
1817
1818 static void check_update_rgn( HWND hwnd, HRGN hrgn )
1819 {
1820     INT ret;
1821     RECT r1, r2;
1822     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
1823     HRGN update = CreateRectRgn( 0, 0, 0, 0 );
1824
1825     ret = GetUpdateRgn( hwnd, update, FALSE );
1826     ok( ret != ERROR, "GetUpdateRgn failed\n" );
1827     if (ret == NULLREGION)
1828     {
1829         ok( !hrgn, "Update region shouldn't be empty\n" );
1830     }
1831     else
1832     {
1833         if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
1834         {
1835             ok( 0, "Regions are different\n" );
1836             if (winetest_debug > 0)
1837             {
1838                 printf( "Update region: " );
1839                 dump_region( update );
1840                 printf( "Wanted region: " );
1841                 dump_region( hrgn );
1842             }
1843         }
1844     }
1845     GetRgnBox( update, &r1 );
1846     GetUpdateRect( hwnd, &r2, FALSE );
1847     ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
1848         "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
1849         r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
1850
1851     DeleteObject( tmp );
1852     DeleteObject( update );
1853 }
1854
1855 static const struct message WmInvalidateRgn[] = {
1856     { WM_NCPAINT, sent },
1857     { WM_GETTEXT, sent|defwinproc|optional },
1858     { 0 }
1859 };
1860
1861 static const struct message WmInvalidateFull[] = {
1862     { WM_NCPAINT, sent|wparam, 1 },
1863     { WM_GETTEXT, sent|defwinproc|optional },
1864     { 0 }
1865 };
1866
1867 static const struct message WmInvalidateErase[] = {
1868     { WM_NCPAINT, sent|wparam, 1 },
1869     { WM_GETTEXT, sent|defwinproc|optional },
1870     { WM_ERASEBKGND, sent },
1871     { 0 }
1872 };
1873
1874 static const struct message WmInvalidatePaint[] = {
1875     { WM_PAINT, sent },
1876     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
1877     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
1878     { 0 }
1879 };
1880
1881 static const struct message WmInvalidateErasePaint[] = {
1882     { WM_PAINT, sent },
1883     { WM_NCPAINT, sent|wparam|beginpaint, 1 },
1884     { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
1885     { WM_ERASEBKGND, sent|beginpaint },
1886     { 0 }
1887 };
1888
1889 static const struct message WmErase[] = {
1890     { WM_ERASEBKGND, sent },
1891     { 0 }
1892 };
1893
1894 static const struct message WmPaint[] = {
1895     { WM_PAINT, sent },
1896     { 0 }
1897 };
1898
1899 static void test_paint_messages(void)
1900 {
1901     RECT rect;
1902     MSG msg;
1903     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1904     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1905     HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
1906                                 100, 100, 200, 200, 0, 0, 0, NULL);
1907     ok (hwnd != 0, "Failed to create overlapped window\n");
1908
1909     ShowWindow( hwnd, SW_SHOW );
1910     UpdateWindow( hwnd );
1911     check_update_rgn( hwnd, 0 );
1912     SetRectRgn( hrgn, 10, 10, 20, 20 );
1913     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
1914     check_update_rgn( hwnd, hrgn );
1915     SetRectRgn( hrgn2, 20, 20, 30, 30 );
1916     RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
1917     CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
1918     check_update_rgn( hwnd, hrgn );
1919     /* validate everything */
1920     RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
1921     check_update_rgn( hwnd, 0 );
1922     /* now with frame */
1923     SetRectRgn( hrgn, -5, -5, 20, 20 );
1924
1925     flush_sequence();
1926     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
1927     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
1928
1929     SetRectRgn( hrgn, 0, 0, 20, 20 );  /* GetUpdateRgn clips to client area */
1930     check_update_rgn( hwnd, hrgn );
1931
1932     flush_sequence();
1933     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
1934     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
1935
1936     flush_sequence();
1937     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
1938     ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
1939
1940     GetClientRect( hwnd, &rect );
1941     SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
1942     check_update_rgn( hwnd, hrgn );
1943
1944     flush_sequence();
1945     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
1946     ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
1947
1948     flush_sequence();
1949     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
1950     ok_sequence( WmInvalidatePaint, "InvalidatePaint", TRUE );
1951     check_update_rgn( hwnd, 0 );
1952
1953     flush_sequence();
1954     RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
1955     ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
1956     check_update_rgn( hwnd, 0 );
1957
1958     flush_sequence();
1959     SetRectRgn( hrgn, 0, 0, 100, 100 );
1960     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
1961     SetRectRgn( hrgn, 0, 0, 50, 100 );
1962     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
1963     SetRectRgn( hrgn, 50, 0, 100, 100 );
1964     check_update_rgn( hwnd, hrgn );
1965     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
1966     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );  /* must not generate messages, everything is valid */
1967     check_update_rgn( hwnd, 0 );
1968
1969     flush_sequence();
1970     SetRectRgn( hrgn, 0, 0, 100, 100 );
1971     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
1972     SetRectRgn( hrgn, 0, 0, 100, 50 );
1973     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
1974     ok_sequence( WmErase, "Erase", FALSE );
1975     SetRectRgn( hrgn, 0, 50, 100, 100 );
1976     check_update_rgn( hwnd, hrgn );
1977
1978     flush_sequence();
1979     SetRectRgn( hrgn, 0, 0, 100, 100 );
1980     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
1981     SetRectRgn( hrgn, 0, 0, 50, 50 );
1982     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
1983     ok_sequence( WmPaint, "Paint", FALSE );
1984
1985     flush_sequence();
1986     SetRectRgn( hrgn, -4, -4, -2, -2 );
1987     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
1988     SetRectRgn( hrgn, -4, -4, -3, -3 );
1989     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
1990     ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
1991
1992     flush_sequence();
1993     SetRectRgn( hrgn, -4, -4, -2, -2 );
1994     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
1995     SetRectRgn( hrgn, -4, -4, -3, -3 );
1996     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
1997     SetRectRgn( hrgn, 0, 0, 1, 1 );
1998     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
1999     ok_sequence( WmPaint, "Paint", TRUE );
2000
2001     flush_sequence();
2002     SetRectRgn( hrgn, -4, -4, -1, -1 );
2003     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2004     RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
2005     /* make sure no WM_PAINT was generated */
2006     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
2007     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2008
2009     flush_sequence();
2010     SetRectRgn( hrgn, -4, -4, -1, -1 );
2011     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
2012     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
2013     {
2014         if (msg.hwnd == hwnd && msg.message == WM_PAINT)
2015         {
2016             /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
2017             INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
2018             ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
2019             ret = GetUpdateRect( hwnd, &rect, FALSE );
2020             ok( ret, "Invalid GetUpdateRect result %d\n", ret );
2021             /* this will send WM_NCPAINT and validate the non client area */
2022             ret = GetUpdateRect( hwnd, &rect, TRUE );
2023             ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
2024         }
2025         else DispatchMessage( &msg );
2026     }
2027     ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
2028
2029     DeleteObject( hrgn );
2030     DeleteObject( hrgn2 );
2031     DestroyWindow( hwnd );
2032 }
2033
2034
2035 /************* window procedures ********************/
2036
2037 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2038 {
2039     static long defwndproc_counter = 0;
2040     static long beginpaint_counter = 0;
2041     LRESULT ret;
2042     struct message msg;
2043
2044     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2045
2046     msg.message = message;
2047     msg.flags = sent|wparam|lparam;
2048     if (defwndproc_counter) msg.flags |= defwinproc;
2049     if (beginpaint_counter) msg.flags |= beginpaint;
2050     msg.wParam = wParam;
2051     msg.lParam = lParam;
2052     add_message(&msg);
2053
2054     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
2055     {
2056         HWND parent = GetParent(hwnd);
2057         RECT rc;
2058         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
2059
2060         GetClientRect(parent, &rc);
2061         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
2062
2063         trace("ptReserved = (%ld,%ld)\n"
2064               "ptMaxSize = (%ld,%ld)\n"
2065               "ptMaxPosition = (%ld,%ld)\n"
2066               "ptMinTrackSize = (%ld,%ld)\n"
2067               "ptMaxTrackSize = (%ld,%ld)\n",
2068               minmax->ptReserved.x, minmax->ptReserved.y,
2069               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
2070               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
2071               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
2072               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
2073
2074         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
2075            minmax->ptMaxSize.x, rc.right);
2076         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
2077            minmax->ptMaxSize.y, rc.bottom);
2078     }
2079
2080     if (message == WM_PAINT)
2081     {
2082         PAINTSTRUCT ps;
2083         beginpaint_counter++;
2084         BeginPaint( hwnd, &ps );
2085         beginpaint_counter--;
2086         EndPaint( hwnd, &ps );
2087         return 0;
2088     }
2089
2090     defwndproc_counter++;
2091     ret = DefWindowProcA(hwnd, message, wParam, lParam);
2092     defwndproc_counter--;
2093
2094     return ret;
2095 }
2096
2097 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2098 {
2099     static long defwndproc_counter = 0;
2100     LRESULT ret;
2101     struct message msg;
2102
2103     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2104
2105     msg.message = message;
2106     msg.flags = sent|wparam|lparam;
2107     if (defwndproc_counter) msg.flags |= defwinproc;
2108     msg.wParam = wParam;
2109     msg.lParam = lParam;
2110     add_message(&msg);
2111
2112     if (message == WM_CREATE)
2113     {
2114         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
2115         SetWindowLongA(hwnd, GWL_STYLE, style);
2116     }
2117
2118     defwndproc_counter++;
2119     ret = DefWindowProcA(hwnd, message, wParam, lParam);
2120     defwndproc_counter--;
2121
2122     return ret;
2123 }
2124
2125 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2126 {
2127     static long defwndproc_counter = 0;
2128     LRESULT ret;
2129     struct message msg;
2130
2131     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2132
2133     if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
2134         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
2135         message == WM_ENABLE || message == WM_ENTERIDLE ||
2136         message == WM_IME_SETCONTEXT)
2137     {
2138         msg.message = message;
2139         msg.flags = sent|parent|wparam|lparam;
2140         if (defwndproc_counter) msg.flags |= defwinproc;
2141         msg.wParam = wParam;
2142         msg.lParam = lParam;
2143         add_message(&msg);
2144     }
2145
2146     defwndproc_counter++;
2147     ret = DefWindowProcA(hwnd, message, wParam, lParam);
2148     defwndproc_counter--;
2149
2150     return ret;
2151 }
2152
2153 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2154 {
2155     static long defwndproc_counter = 0;
2156     LRESULT ret;
2157     struct message msg;
2158
2159     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
2160
2161     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
2162     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
2163     if (after_end_dialog)
2164         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
2165     else
2166         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
2167
2168     msg.message = message;
2169     msg.flags = sent|wparam|lparam;
2170     if (defwndproc_counter) msg.flags |= defwinproc;
2171     msg.wParam = wParam;
2172     msg.lParam = lParam;
2173     add_message(&msg);
2174
2175     defwndproc_counter++;
2176     ret = DefDlgProcA(hwnd, message, wParam, lParam);
2177     defwndproc_counter--;
2178
2179     return ret;
2180 }
2181
2182 static BOOL RegisterWindowClasses(void)
2183 {
2184     WNDCLASSA cls;
2185
2186     cls.style = 0;
2187     cls.lpfnWndProc = MsgCheckProcA;
2188     cls.cbClsExtra = 0;
2189     cls.cbWndExtra = 0;
2190     cls.hInstance = GetModuleHandleA(0);
2191     cls.hIcon = 0;
2192     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2193     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2194     cls.lpszMenuName = NULL;
2195     cls.lpszClassName = "TestWindowClass";
2196     if(!RegisterClassA(&cls)) return FALSE;
2197
2198     cls.lpfnWndProc = PopupMsgCheckProcA;
2199     cls.lpszClassName = "TestPopupClass";
2200     if(!RegisterClassA(&cls)) return FALSE;
2201
2202     cls.lpfnWndProc = ParentMsgCheckProcA;
2203     cls.lpszClassName = "TestParentClass";
2204     if(!RegisterClassA(&cls)) return FALSE;
2205
2206     cls.lpfnWndProc = DefWindowProcA;
2207     cls.lpszClassName = "SimpleWindowClass";
2208     if(!RegisterClassA(&cls)) return FALSE;
2209
2210     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
2211     cls.lpfnWndProc = TestDlgProcA;
2212     cls.lpszClassName = "TestDialogClass";
2213     if(!RegisterClassA(&cls)) return FALSE;
2214
2215     return TRUE;
2216 }
2217
2218 static HHOOK hCBT_hook;
2219
2220 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
2221
2222     char buf[256];
2223
2224     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
2225
2226     /* Log also SetFocus(0) calls */
2227     if (!wParam) wParam = lParam;
2228
2229     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
2230     {
2231         if (!strcmp(buf, "TestWindowClass") ||
2232             !strcmp(buf, "TestParentClass") ||
2233             !strcmp(buf, "TestPopupClass") ||
2234             !strcmp(buf, "SimpleWindowClass") ||
2235             !strcmp(buf, "TestDialogClass") ||
2236             !strcmp(buf, "MDI_frame_class") ||
2237             !strcmp(buf, "MDI_client_class") ||
2238             !strcmp(buf, "MDI_child_class") ||
2239             !strcmp(buf, "my_button_class") ||
2240             !strcmp(buf, "#32770"))
2241         {
2242             struct message msg;
2243
2244             msg.message = nCode;
2245             msg.flags = hook;
2246             msg.wParam = wParam;
2247             msg.lParam = lParam;
2248             add_message(&msg);
2249         }
2250     }
2251     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
2252 }
2253
2254 START_TEST(msg)
2255 {
2256     if (!RegisterWindowClasses()) assert(0);
2257
2258     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
2259     assert(hCBT_hook);
2260
2261     test_messages();
2262     test_mdi_messages();
2263     test_button_messages();
2264     test_paint_messages();
2265
2266     UnhookWindowsHookEx(hCBT_hook);
2267 }