EnableWindow should not remove the focus of child windows.
[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
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30
31 #include "wine/test.h"
32
33
34 /*
35 FIXME: add tests for these
36 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
37  WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
38  WS_THICKFRAME: thick border
39  WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
40  WS_BORDER (default for overlapped windows): single black border
41  none (default for child (and popup?) windows): no border
42 */
43
44 typedef enum { 
45     sent=0x1, posted=0x2, parent=0x4, wparam=0x8, lparam=0x10,
46     defwinproc=0x20, optional=0x40, hook=0x80
47 } msg_flags_t;
48
49 struct message {
50     UINT message;          /* the WM_* code */
51     msg_flags_t flags;     /* message props */
52     WPARAM wParam;         /* expected value of wParam */
53     LPARAM lParam;         /* expected value of lParam */
54 };
55
56 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
57 static const struct message WmCreateOverlappedSeq[] = {
58     { HCBT_CREATEWND, hook },
59     { WM_GETMINMAXINFO, sent },
60     { WM_NCCREATE, sent },
61     { WM_NCCALCSIZE, sent|wparam, 0 },
62     { WM_CREATE, sent },
63     { 0 }
64 };
65 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
66  * for a not visible overlapped window.
67  */
68 static const struct message WmSWP_ShowOverlappedSeq[] = {
69     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
70     { WM_NCPAINT, sent|wparam|optional, 1 },
71     { WM_GETTEXT, sent|defwinproc|optional },
72     { WM_ERASEBKGND, sent|optional },
73     { HCBT_ACTIVATE, hook },
74     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
75     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 }, /* Win9x: SWP_NOSENDCHANGING */
76     { WM_ACTIVATEAPP, sent|wparam, 1 },
77     { WM_NCACTIVATE, sent|wparam, 1 },
78     { WM_GETTEXT, sent|defwinproc|optional },
79     { WM_ACTIVATE, sent|wparam, 1 },
80     { HCBT_SETFOCUS, hook },
81     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
82     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
83     { WM_NCPAINT, sent|wparam|optional, 1 },
84     { WM_GETTEXT, sent|defwinproc|optional },
85     { WM_ERASEBKGND, sent|optional },
86     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
87     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
88     { WM_NCPAINT, sent|wparam|optional, 1 },
89     { WM_ERASEBKGND, sent|optional },
90     { 0 }
91 };
92 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
93  * for a visible overlapped window.
94  */
95 static const struct message WmSWP_HideOverlappedSeq[] = {
96     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
97     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
98     { 0 }
99 };
100 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
101 static const struct message WmShowOverlappedSeq[] = {
102     { WM_SHOWWINDOW, sent|wparam, 1 },
103     { WM_NCPAINT, sent|wparam|optional, 1 },
104     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
105     { WM_NCPAINT, sent|wparam|optional, 1 },
106     { WM_GETTEXT, sent|defwinproc|optional },
107     { WM_ERASEBKGND, sent|optional },
108     { HCBT_ACTIVATE, hook },
109     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
110     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
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_SETFOCUS, sent|wparam|defwinproc, 0 },
118     { WM_NCPAINT, sent|wparam|optional, 1 },
119     { WM_GETTEXT, sent|defwinproc|optional },
120     { WM_ERASEBKGND, sent|optional },
121     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
122     { WM_NCCALCSIZE, sent|optional },
123     { WM_NCPAINT, sent|optional },
124     { WM_ERASEBKGND, sent|optional },
125 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
126        * messages. Does that mean that CreateWindow doesn't set initial
127        * window dimensions for overlapped windows?
128        */
129     { WM_SIZE, sent },
130     { WM_MOVE, sent },
131 #endif
132     { 0 }
133 };
134 /* ShowWindow(SW_HIDE) for a visible overlapped window */
135 static const struct message WmHideOverlappedSeq[] = {
136     { WM_SHOWWINDOW, sent|wparam, 0 },
137     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
138     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
139     { WM_SIZE, sent },
140     { WM_MOVE, sent },
141     { WM_NCACTIVATE, sent|wparam, 0 },
142     { WM_ACTIVATE, sent|wparam, 0 },
143     { WM_ACTIVATEAPP, sent|wparam, 0 },
144     { WM_KILLFOCUS, sent|wparam, 0 },
145     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
146     { 0 }
147 };
148 /* DestroyWindow for a visible overlapped window */
149 static const struct message WmDestroyOverlappedSeq[] = {
150     { HCBT_DESTROYWND, hook },
151     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
152     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
153     { WM_NCACTIVATE, sent|wparam, 0 },
154     { WM_ACTIVATE, sent|wparam, 0 },
155     { WM_ACTIVATEAPP, sent|wparam, 0 },
156     { WM_KILLFOCUS, sent|wparam, 0 },
157     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
158     { WM_DESTROY, sent },
159     { WM_NCDESTROY, sent },
160     { 0 }
161 };
162 /* CreateWindow (for a child popup window, not initially visible) */
163 static const struct message WmCreateChildPopupSeq[] = {
164     { HCBT_CREATEWND, hook },
165     { WM_NCCREATE, sent }, 
166     { WM_NCCALCSIZE, sent|wparam, 0 },
167     { WM_CREATE, sent },
168     { WM_SIZE, sent },
169     { WM_MOVE, sent },
170     { 0 }
171 };
172 /* CreateWindow (for a popup window, not initially visible,
173  * which sets WS_VISIBLE in WM_CREATE handler)
174  */
175 static const struct message WmCreateInvisiblePopupSeq[] = {
176     { HCBT_CREATEWND, hook },
177     { WM_NCCREATE, sent }, 
178     { WM_NCCALCSIZE, sent|wparam, 0 },
179     { WM_CREATE, sent },
180     { WM_STYLECHANGING, sent },
181     { WM_STYLECHANGED, sent },
182     { WM_SIZE, sent },
183     { WM_MOVE, sent },
184     { 0 }
185 };
186 /* ShowWindow (for a popup window with WS_VISIBLE style set) */
187 static const struct message WmShowVisiblePopupSeq[] = {
188     { 0 }
189 };
190 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
191  * for a popup window with WS_VISIBLE style set
192  */
193 static const struct message WmShowVisiblePopupSeq_2[] = {
194     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
195     { 0 }
196 };
197 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
198  * for a popup window with WS_VISIBLE style set
199  */
200 static const struct message WmShowVisiblePopupSeq_3[] = {
201     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
202     { HCBT_ACTIVATE, hook },
203     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
204     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
205     { WM_NCACTIVATE, sent|wparam, 1 },
206     { WM_ACTIVATE, sent|wparam, 1 },
207     { HCBT_SETFOCUS, hook },
208     { WM_KILLFOCUS, sent|parent },
209     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
210     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
211     { WM_SETFOCUS, sent|defwinproc },
212     { 0 }
213 };
214 /* CreateWindow (for child window, not initially visible) */
215 static const struct message WmCreateChildSeq[] = {
216     { HCBT_CREATEWND, hook },
217     { WM_NCCREATE, sent }, 
218     /* child is inserted into parent's child list after WM_NCCREATE returns */
219     { WM_NCCALCSIZE, sent|wparam, 0 },
220     { WM_CREATE, sent },
221     { WM_SIZE, sent },
222     { WM_MOVE, sent },
223     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
224     { 0 }
225 };
226 /* CreateWindow (for maximized child window, not initially visible) */
227 static const struct message WmCreateMaximizedChildSeq[] = {
228     { HCBT_CREATEWND, hook },
229     { WM_NCCREATE, sent }, 
230     { WM_NCCALCSIZE, sent|wparam, 0 },
231     { WM_CREATE, sent },
232     { WM_SIZE, sent },
233     { WM_MOVE, sent },
234     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
235     { WM_GETMINMAXINFO, sent },
236     { WM_WINDOWPOSCHANGING, sent },
237     { WM_NCCALCSIZE, sent },
238     { WM_WINDOWPOSCHANGED, sent },
239     { WM_SIZE, sent|defwinproc },
240     { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
241     { 0 }
242 };
243 /* ShowWindow(SW_SHOW) for a not visible child window */
244 static const struct message WmShowChildSeq[] = {
245     { WM_SHOWWINDOW, sent|wparam, 1 },
246     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
247     { WM_ERASEBKGND, sent|parent|optional },
248     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
249     { 0 }
250 };
251 /* DestroyWindow for a visible child window */
252 static const struct message WmDestroyChildSeq[] = {
253     { HCBT_DESTROYWND, hook },
254     { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
255     { WM_SHOWWINDOW, sent|wparam, 0 },
256     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
257     { WM_ERASEBKGND, sent|parent|optional },
258     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
259     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
260     { WM_KILLFOCUS, sent },
261     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
262     { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
263     { WM_SETFOCUS, sent|parent },
264     { WM_DESTROY, sent },
265     { WM_DESTROY, sent|optional }, /* a bug in win2k sp4 ? */
266     { WM_NCDESTROY, sent },
267     { WM_NCDESTROY, sent|optional }, /* a bug in win2k sp4 ? */
268     { 0 }
269 };
270 /* Moving the mouse in nonclient area */
271 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
272     { WM_NCHITTEST, sent },
273     { WM_SETCURSOR, sent },
274     { WM_NCMOUSEMOVE, posted },
275     { 0 }
276 };
277 /* Moving the mouse in client area */
278 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
279     { WM_NCHITTEST, sent },
280     { WM_SETCURSOR, sent },
281     { WM_MOUSEMOVE, posted },
282     { 0 }
283 };
284 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
285 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
286     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
287     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
288     { WM_GETMINMAXINFO, sent|defwinproc },
289     { WM_ENTERSIZEMOVE, sent|defwinproc },
290     { WM_WINDOWPOSCHANGING, sent|defwinproc },
291     { WM_WINDOWPOSCHANGED, sent|defwinproc },
292     { WM_MOVE, sent|defwinproc },
293     { WM_EXITSIZEMOVE, sent|defwinproc },
294     { 0 }
295 };
296 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
297 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
298     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
299     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
300     { WM_GETMINMAXINFO, sent|defwinproc },
301     { WM_ENTERSIZEMOVE, sent|defwinproc },
302     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
303     { WM_WINDOWPOSCHANGING, sent|defwinproc },
304     { WM_GETMINMAXINFO, sent|defwinproc },
305     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
306     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
307     { WM_GETTEXT, sent|defwinproc },
308     { WM_ERASEBKGND, sent|defwinproc },
309     { WM_WINDOWPOSCHANGED, sent|defwinproc },
310     { WM_MOVE, sent|defwinproc },
311     { WM_SIZE, sent|defwinproc },
312     { WM_EXITSIZEMOVE, sent|defwinproc },
313     { 0 }
314 };
315 /* Resizing child window with MoveWindow (32) */
316 static const struct message WmResizingChildWithMoveWindowSeq[] = {
317     { WM_WINDOWPOSCHANGING, sent },
318     { WM_NCCALCSIZE, sent|wparam, 1 },
319     { WM_ERASEBKGND, sent|optional },
320     { WM_WINDOWPOSCHANGED, sent },
321     { WM_MOVE, sent|defwinproc },
322     { WM_SIZE, sent|defwinproc },
323     { 0 }
324 };
325 /* Clicking on inactive button */
326 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
327     { WM_NCHITTEST, sent },
328     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
329     { WM_MOUSEACTIVATE, sent },
330     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
331     { WM_SETCURSOR, sent },
332     { WM_SETCURSOR, sent|parent|defwinproc },
333     { WM_LBUTTONDOWN, posted },
334     { WM_KILLFOCUS, posted|parent },
335     { WM_SETFOCUS, posted },
336     { WM_CTLCOLORBTN, posted|parent },
337     { BM_SETSTATE, posted },
338     { WM_CTLCOLORBTN, posted|parent },
339     { WM_LBUTTONUP, posted },
340     { BM_SETSTATE, posted },
341     { WM_CTLCOLORBTN, posted|parent },
342     { WM_COMMAND, posted|parent },
343     { 0 }
344 };
345 /* Reparenting a button (16/32) */
346 /* The last child (button) reparented gets topmost for its new parent. */
347 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
348     { WM_SHOWWINDOW, sent|wparam, 0 },
349     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
350     { WM_ERASEBKGND, sent|parent },
351     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
352     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
353     { WM_CHILDACTIVATE, sent },
354     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
355     { WM_MOVE, sent|defwinproc },
356     { WM_SHOWWINDOW, sent|wparam, 1 },
357     { 0 }
358 };
359 /* Creation of a custom dialog (32) */
360 static const struct message WmCreateCustomDialogSeq[] = {
361     { HCBT_CREATEWND, hook },
362     { WM_GETMINMAXINFO, sent },
363     { WM_NCCREATE, sent },
364     { WM_NCCALCSIZE, sent|wparam, 0 },
365     { WM_CREATE, sent },
366     { WM_SHOWWINDOW, sent|wparam, 1 },
367     { HCBT_ACTIVATE, hook },
368     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
369     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
370     { WM_NCACTIVATE, sent|wparam, 1 },
371     { WM_GETTEXT, sent|optional|defwinproc },
372     { WM_GETICON, sent|optional|defwinproc },
373     { WM_GETICON, sent|optional|defwinproc },
374     { WM_GETICON, sent|optional|defwinproc },
375     { WM_GETTEXT, sent|optional|defwinproc },
376     { WM_ACTIVATE, sent|wparam, 1 },
377     { WM_KILLFOCUS, sent|parent },
378     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
379     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
380     { WM_SETFOCUS, sent },
381     { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
382     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
383     { WM_NCPAINT, sent|wparam, 1 },
384     { WM_GETTEXT, sent|optional|defwinproc },
385     { WM_GETICON, sent|optional|defwinproc },
386     { WM_GETICON, sent|optional|defwinproc },
387     { WM_GETICON, sent|optional|defwinproc },
388     { WM_GETTEXT, sent|optional|defwinproc },
389     { WM_ERASEBKGND, sent },
390     { WM_CTLCOLORDLG, sent|defwinproc },
391     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
392     { WM_GETTEXT, sent|optional },
393     { WM_GETICON, sent|optional },
394     { WM_GETICON, sent|optional },
395     { WM_GETICON, sent|optional },
396     { WM_GETTEXT, sent|optional },
397     { WM_NCCALCSIZE, sent|optional },
398     { WM_NCPAINT, sent|optional },
399     { WM_GETTEXT, sent|optional|defwinproc },
400     { WM_GETICON, sent|optional|defwinproc },
401     { WM_GETICON, sent|optional|defwinproc },
402     { WM_GETICON, sent|optional|defwinproc },
403     { WM_GETTEXT, sent|optional|defwinproc },
404     { WM_ERASEBKGND, sent|optional },
405     { WM_CTLCOLORDLG, sent|optional|defwinproc },
406     { WM_SIZE, sent },
407     { WM_MOVE, sent },
408     { 0 }
409 };
410 /* Calling EndDialog for a custom dialog (32) */
411 static const struct message WmEndCustomDialogSeq[] = {
412     { WM_WINDOWPOSCHANGING, sent },
413     { WM_WINDOWPOSCHANGED, sent },
414     { WM_GETTEXT, sent|optional },
415     { WM_GETICON, sent|optional },
416     { WM_GETICON, sent|optional },
417     { WM_GETICON, sent|optional },
418     { HCBT_ACTIVATE, hook },
419     { WM_NCACTIVATE, sent|wparam, 0 },
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, 0 },
426     { WM_WINDOWPOSCHANGING, sent|optional },
427     { HCBT_SETFOCUS, hook },
428     { WM_KILLFOCUS, sent },
429     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
430     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
431     { WM_SETFOCUS, sent|parent|defwinproc },
432     { 0 }
433 };
434 /* Creation and destruction of a modal dialog (32) */
435 static const struct message WmModalDialogSeq[] = {
436     { WM_CANCELMODE, sent|parent },
437     { WM_KILLFOCUS, sent|parent },
438     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
439     { WM_ENABLE, sent|parent|wparam, 0 },
440     { HCBT_CREATEWND, hook },
441     { WM_SETFONT, sent },
442     { WM_INITDIALOG, sent },
443     { WM_CHANGEUISTATE, sent|optional },
444     { WM_SHOWWINDOW, sent },
445     { HCBT_ACTIVATE, hook },
446     { WM_WINDOWPOSCHANGING, sent },
447     { WM_NCACTIVATE, sent|wparam, 1 },
448     { WM_GETICON, sent|optional },
449     { WM_GETICON, sent|optional },
450     { WM_GETICON, sent|optional },
451     { WM_GETTEXT, sent|optional },
452     { WM_ACTIVATE, sent|wparam, 1 },
453     { WM_WINDOWPOSCHANGING, sent },
454     { WM_NCPAINT, sent },
455     { WM_GETICON, sent|optional },
456     { WM_GETICON, sent|optional },
457     { WM_GETICON, sent|optional },
458     { WM_GETTEXT, sent|optional },
459     { WM_ERASEBKGND, sent },
460     { WM_CTLCOLORDLG, sent },
461     { WM_WINDOWPOSCHANGED, sent },
462     { WM_GETICON, sent|optional },
463     { WM_GETICON, sent|optional },
464     { WM_GETICON, sent|optional },
465     { WM_GETTEXT, sent|optional },
466     { WM_NCCALCSIZE, sent|optional },
467     { WM_NCPAINT, sent|optional },
468     { WM_GETICON, sent|optional },
469     { WM_GETICON, sent|optional },
470     { WM_GETICON, sent|optional },
471     { WM_GETTEXT, sent|optional },
472     { WM_ERASEBKGND, sent|optional },
473     { WM_CTLCOLORDLG, sent|optional },
474     { WM_PAINT, sent|optional },
475     { WM_CTLCOLORBTN, sent },
476     { WM_ENTERIDLE, sent|parent },
477     { WM_TIMER, sent },
478     { WM_ENABLE, sent|parent|wparam, 1 },
479     { WM_WINDOWPOSCHANGING, sent },
480     { WM_WINDOWPOSCHANGED, sent },
481     { WM_GETICON, sent|optional },
482     { WM_GETICON, sent|optional },
483     { WM_GETICON, sent|optional },
484     { WM_GETTEXT, sent|optional },
485     { HCBT_ACTIVATE, hook },
486     { WM_NCACTIVATE, sent|wparam, 0 },
487     { WM_GETICON, sent|optional },
488     { WM_GETICON, sent|optional },
489     { WM_GETICON, sent|optional },
490     { WM_GETTEXT, sent|optional },
491     { WM_ACTIVATE, sent|wparam, 0 },
492     { WM_WINDOWPOSCHANGING, sent|optional },
493     { HCBT_SETFOCUS, hook },
494     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
495     { WM_SETFOCUS, sent|parent|defwinproc },
496     { HCBT_DESTROYWND, hook },
497     { WM_DESTROY, sent },
498     { WM_NCDESTROY, sent },
499     { 0 }
500 };
501 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
502 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
503     /* (inside dialog proc, handling WM_INITDIALOG) */
504     { WM_WINDOWPOSCHANGING, sent },
505     { WM_NCCALCSIZE, sent },
506     { WM_NCACTIVATE, sent|parent|wparam, 0 },
507     { WM_GETTEXT, sent|defwinproc },
508     { WM_ACTIVATE, sent|parent|wparam, 0 },
509     { WM_WINDOWPOSCHANGING, sent },
510     { WM_WINDOWPOSCHANGING, sent|parent },
511     { WM_NCACTIVATE, sent|wparam, 1 },
512     { WM_ACTIVATE, sent|wparam, 1 },
513     { WM_WINDOWPOSCHANGED, sent },
514     { WM_SIZE, sent|defwinproc },
515     /* (setting focus) */
516     { WM_SHOWWINDOW, sent|wparam, 1 },
517     { WM_WINDOWPOSCHANGING, sent },
518     { WM_NCPAINT, sent },
519     { WM_GETTEXT, sent|defwinproc },
520     { WM_ERASEBKGND, sent },
521     { WM_CTLCOLORDLG, sent|defwinproc },
522     { WM_WINDOWPOSCHANGED, sent },
523     { WM_PAINT, sent },
524     /* (bunch of WM_CTLCOLOR* for each control) */
525     { WM_PAINT, sent|parent },
526     { WM_ENTERIDLE, sent|parent|wparam, 0 },
527     { WM_SETCURSOR, sent|parent },
528     { 0 }
529 };
530 /* SetMenu for NonVisible windows with size change*/
531 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
532     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
533     { WM_NCCALCSIZE, sent|wparam, 1 },
534     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
535     { WM_MOVE, sent|defwinproc },
536     { WM_SIZE, sent|defwinproc },
537     { WM_GETICON, sent|optional },
538     { WM_GETICON, sent|optional },
539     { WM_GETICON, sent|optional },
540     { WM_GETTEXT, sent|optional },
541     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
542     { 0 }
543 };
544 /* SetMenu for NonVisible windows with no size change */
545 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
546     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
547     { WM_NCCALCSIZE, sent|wparam, 1 },
548     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
549     { 0 }
550 };
551 /* SetMenu for Visible windows with size change */
552 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
553     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
554     { WM_NCCALCSIZE, sent|wparam, 1 },
555     { WM_NCPAINT, sent|wparam, 1 },
556     { WM_GETTEXT, sent|defwinproc|optional },
557     { WM_ERASEBKGND, sent|optional },
558     { WM_ACTIVATE, sent|optional },
559     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
560     { WM_MOVE, sent|defwinproc },
561     { WM_SIZE, sent|defwinproc },
562     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
563     { WM_NCPAINT, sent|wparam|optional, 1 },
564     { WM_ERASEBKGND, sent|optional },
565     { 0 }
566 };
567 /* SetMenu for Visible windows with no size change */
568 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
569     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
570     { WM_NCCALCSIZE, sent|wparam, 1 },
571     { WM_NCPAINT, sent|wparam, 1 },
572     { WM_GETTEXT, sent|defwinproc|optional },
573     { WM_ERASEBKGND, sent|optional },
574     { WM_ACTIVATE, sent|optional },
575     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
576     { 0 }
577 };
578 /* DrawMenuBar for a visible window */
579 static const struct message WmDrawMenuBarSeq[] =
580 {
581     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
582     { WM_NCCALCSIZE, sent|wparam, 1 },
583     { WM_NCPAINT, sent|wparam, 1 },
584     { WM_GETTEXT, sent|defwinproc|optional },
585     { WM_ERASEBKGND, sent|optional },
586     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
587     { 0 }
588 };
589
590 static const struct message WmSetRedrawFalseSeq[] =
591 {
592     { WM_SETREDRAW, sent|wparam, 0 },
593     { 0 }
594 };
595
596 static const struct message WmSetRedrawTrueSeq[] =
597 {
598     { WM_SETREDRAW, sent|wparam, 1 },
599     { 0 }
600 };
601
602 static const struct message WmEnableWindowSeq[] =
603 {
604     { WM_CANCELMODE, sent },
605     { WM_ENABLE, sent },
606     { 0 }
607 };
608
609 static int after_end_dialog;
610 static int sequence_cnt, sequence_size;
611 static struct message* sequence;
612
613 static void add_message(const struct message *msg)
614 {
615     if (!sequence) 
616     {
617         sequence_size = 10;
618         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
619     }
620     if (sequence_cnt == sequence_size) 
621     {
622         sequence_size *= 2;
623         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
624     }
625     assert(sequence);
626
627     sequence[sequence_cnt].message = msg->message;
628     sequence[sequence_cnt].flags = msg->flags;
629     sequence[sequence_cnt].wParam = msg->wParam;
630     sequence[sequence_cnt].lParam = msg->lParam;
631
632     sequence_cnt++;
633 }
634
635 static void flush_sequence()
636 {
637     HeapFree(GetProcessHeap(), 0, sequence);
638     sequence = 0;
639     sequence_cnt = sequence_size = 0;
640 }
641
642 static void ok_sequence(const struct message *expected, const char *context)
643 {
644     static const struct message end_of_sequence = { 0, 0, 0, 0 };
645     const struct message *actual;
646     
647     add_message(&end_of_sequence);
648
649     actual = sequence;
650
651     while (expected->message && actual->message)
652     {
653         trace("expected %04x - actual %04x\n", expected->message, actual->message);
654
655         if (expected->message == actual->message)
656         {
657             if (expected->flags & wparam)
658                  ok (expected->wParam == actual->wParam,
659                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
660                      context, expected->message, expected->wParam, actual->wParam);
661             if (expected->flags & lparam)
662                  ok (expected->lParam == actual->lParam,
663                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
664                      context, expected->message, expected->lParam, actual->lParam);
665             ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
666                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
667                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
668             ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
669                 "%s: the msg 0x%04x should have been %s\n",
670                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
671             ok ((expected->flags & parent) == (actual->flags & parent),
672                 "%s: the msg 0x%04x was expected in %s\n",
673                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
674             ok ((expected->flags & hook) == (actual->flags & hook),
675                 "%s: the msg 0x%04x should have been sent by a hook\n",
676                 context, expected->message);
677             expected++;
678             actual++;
679         }
680         else if (expected->flags & optional)
681             expected++;
682         else
683         {
684           todo_wine {
685             ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
686                 context, expected->message, actual->message);
687             expected++;
688             actual++;
689           }
690         }
691     }
692
693     /* skip all optional trailing messages */
694     while (expected->message && (expected->flags & optional))
695         expected++;
696
697   todo_wine {
698     if (expected->message || actual->message)
699         ok (FALSE, "%s: the msg sequence is not complete (got 0x%04x)\n", context, actual->message);
700   }
701
702     flush_sequence();
703 }
704
705 static void test_WM_SETREDRAW(HWND hwnd)
706 {
707     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
708
709     flush_sequence();
710
711     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
712     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE");
713
714     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
715     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
716
717     flush_sequence();
718     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
719     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE");
720
721     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
722     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
723
724     /* restore original WS_VISIBLE state */
725     SetWindowLongA(hwnd, GWL_STYLE, style);
726
727     flush_sequence();
728 }
729
730 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
731 {
732     struct message msg;
733
734     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
735
736     msg.message = message;
737     msg.flags = sent|wparam|lparam;
738     msg.wParam = wParam;
739     msg.lParam = lParam;
740     add_message(&msg);
741
742     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
743     if (message == WM_TIMER) EndDialog( hwnd, 0 );
744     return 0;
745 }
746
747 /* test if we receive the right sequence of messages */
748 static void test_messages(void)
749 {
750     HWND hwnd, hparent, hchild;
751     HWND hchild2, hbutton;
752     HMENU hmenu;
753
754     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
755                            100, 100, 200, 200, 0, 0, 0, NULL);
756     ok (hwnd != 0, "Failed to create overlapped window\n");
757     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
758
759     /* test WM_SETREDRAW on a not visible top level window */
760     test_WM_SETREDRAW(hwnd);
761
762     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
763     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped");
764     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
765
766     ok(GetActiveWindow() == hwnd, "window should be active\n");
767     ok(GetFocus() == hwnd, "window should have input focus\n");
768     ShowWindow(hwnd, SW_HIDE);
769     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped");
770     
771     ShowWindow(hwnd, SW_SHOW);
772     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped");
773
774     ok(GetActiveWindow() == hwnd, "window should be active\n");
775     ok(GetFocus() == hwnd, "window should have input focus\n");
776     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
777     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped");
778     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
779
780     /* test WM_SETREDRAW on a visible top level window */
781     ShowWindow(hwnd, SW_SHOW);
782     test_WM_SETREDRAW(hwnd);
783
784     DestroyWindow(hwnd);
785     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped");
786
787     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
788                               100, 100, 200, 200, 0, 0, 0, NULL);
789     ok (hparent != 0, "Failed to create parent window\n");
790     flush_sequence();
791
792     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
793                              0, 0, 10, 10, hparent, 0, 0, NULL);
794     ok (hchild != 0, "Failed to create child window\n");
795     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child");
796     DestroyWindow(hchild);
797     flush_sequence();
798
799     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW,
800                              0, 0, 10, 10, hparent, 0, 0, NULL);
801     ok (hchild != 0, "Failed to create child window\n");
802     ok_sequence(WmCreateChildSeq, "CreateWindow:child");
803     
804     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILDWINDOW,
805                                100, 100, 50, 50, hparent, 0, 0, NULL);
806     ok (hchild2 != 0, "Failed to create child2 window\n");
807     flush_sequence();
808
809     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILDWINDOW,
810                               0, 100, 50, 50, hchild, 0, 0, NULL);
811     ok (hbutton != 0, "Failed to create button window\n");
812
813     /* test WM_SETREDRAW on a not visible child window */
814     test_WM_SETREDRAW(hchild);
815
816     ShowWindow(hchild, SW_SHOW);
817     ok_sequence(WmShowChildSeq, "ShowWindow:child");
818
819     /* test WM_SETREDRAW on a visible child window */
820     test_WM_SETREDRAW(hchild);
821
822     SetFocus(hchild);
823     flush_sequence();
824
825     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
826     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child");
827
828     DestroyWindow(hchild);
829     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child");
830     DestroyWindow(hchild2);
831     DestroyWindow(hbutton);
832
833     flush_sequence();
834     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
835                              0, 0, 100, 100, hparent, 0, 0, NULL);
836     ok (hchild != 0, "Failed to create child popup window\n");
837     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup");
838     DestroyWindow(hchild);
839
840     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
841     flush_sequence();
842     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
843                              0, 0, 100, 100, hparent, 0, 0, NULL);
844     ok (hchild != 0, "Failed to create popup window\n");
845     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
846     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
847     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
848     flush_sequence();
849     ShowWindow(hchild, SW_SHOW);
850     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
851     flush_sequence();
852     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
853     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
854     flush_sequence();
855     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
856     ok_sequence(WmShowVisiblePopupSeq_3, "CreateWindow:show_visible_popup_3");
857     DestroyWindow(hchild);
858
859     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
860      * changes nothing in message sequences.
861      */
862     flush_sequence();
863     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
864                              0, 0, 100, 100, hparent, 0, 0, NULL);
865     ok (hchild != 0, "Failed to create popup window\n");
866     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
867     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
868     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
869     flush_sequence();
870     ShowWindow(hchild, SW_SHOW);
871     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
872     flush_sequence();
873     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
874     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
875     DestroyWindow(hchild);
876
877     flush_sequence();
878     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
879                            0, 0, 100, 100, hparent, 0, 0, NULL);
880     ok(hwnd != 0, "Failed to create custom dialog window\n");
881     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog");
882
883     flush_sequence();
884     after_end_dialog = 1;
885     EndDialog( hwnd, 0 );
886     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog");
887
888     DestroyWindow(hwnd);
889     after_end_dialog = 0;
890
891     flush_sequence();
892     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
893     ok_sequence(WmModalDialogSeq, "ModalDialog");
894
895     DestroyWindow(hparent);
896     flush_sequence();
897
898     /* Message sequence for SetMenu */
899     hmenu = CreateMenu();
900     ok (hmenu != 0, "Failed to create menu\n");
901     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
902     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
903                            100, 100, 200, 200, 0, hmenu, 0, NULL);
904     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
905     ok (SetMenu(hwnd, 0), "SetMenu\n");
906     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange");
907     ok (SetMenu(hwnd, 0), "SetMenu\n");
908     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange");
909     ShowWindow(hwnd, SW_SHOW);
910     flush_sequence();
911     ok (SetMenu(hwnd, 0), "SetMenu\n");
912     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange");
913     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
914     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange");
915
916     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
917     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar");
918
919     DestroyWindow(hwnd);
920     flush_sequence();
921
922     /* Message sequence for EnableWindow */
923     hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
924                               100, 100, 200, 200, 0, 0, 0, NULL);
925     ok (hparent != 0, "Failed to create parent window\n");
926     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW | WS_VISIBLE,
927                              0, 0, 10, 10, hparent, 0, 0, NULL);
928     ok (hchild != 0, "Failed to create child window\n");
929
930     SetFocus(hchild);
931     flush_sequence();
932
933     EnableWindow(hparent, FALSE);
934     ok_sequence(WmEnableWindowSeq, "EnableWindow");
935
936     DestroyWindow(hparent);
937     flush_sequence();
938 }
939
940 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
941 {
942     static long defwndproc_counter = 0;
943     LRESULT ret;
944     struct message msg;
945
946     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
947
948     msg.message = message;
949     msg.flags = sent|wparam|lparam;
950     if (defwndproc_counter) msg.flags |= defwinproc;
951     msg.wParam = wParam;
952     msg.lParam = lParam;
953     add_message(&msg);
954
955     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
956     {
957         HWND parent = GetParent(hwnd);
958         RECT rc;
959         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
960
961         GetClientRect(parent, &rc);
962         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
963
964         trace("ptReserved = (%ld,%ld)\n"
965               "ptMaxSize = (%ld,%ld)\n"
966               "ptMaxPosition = (%ld,%ld)\n"
967               "ptMinTrackSize = (%ld,%ld)\n"
968               "ptMaxTrackSize = (%ld,%ld)\n",
969               minmax->ptReserved.x, minmax->ptReserved.y,
970               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
971               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
972               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
973               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
974
975         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
976            minmax->ptMaxSize.x, rc.right);
977         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
978            minmax->ptMaxSize.y, rc.bottom);
979     }
980
981     defwndproc_counter++;
982     ret = DefWindowProcA(hwnd, message, wParam, lParam);
983     defwndproc_counter--;
984
985     return ret;
986 }
987
988 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
989 {
990     static long defwndproc_counter = 0;
991     LRESULT ret;
992     struct message msg;
993
994     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
995
996     msg.message = message;
997     msg.flags = sent|wparam|lparam;
998     if (defwndproc_counter) msg.flags |= defwinproc;
999     msg.wParam = wParam;
1000     msg.lParam = lParam;
1001     add_message(&msg);
1002
1003     if (message == WM_CREATE)
1004     {
1005         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
1006         SetWindowLongA(hwnd, GWL_STYLE, style);
1007     }
1008
1009     defwndproc_counter++;
1010     ret = DefWindowProcA(hwnd, message, wParam, lParam);
1011     defwndproc_counter--;
1012
1013     return ret;
1014 }
1015
1016 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1017 {
1018     static long defwndproc_counter = 0;
1019     LRESULT ret;
1020     struct message msg;
1021
1022     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1023
1024     if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
1025         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
1026         message == WM_ENABLE || message == WM_ENTERIDLE ||
1027         message == WM_IME_SETCONTEXT)
1028     {
1029         msg.message = message;
1030         msg.flags = sent|parent|wparam|lparam;
1031         if (defwndproc_counter) msg.flags |= defwinproc;
1032         msg.wParam = wParam;
1033         msg.lParam = lParam;
1034         add_message(&msg);
1035     }
1036
1037     defwndproc_counter++;
1038     ret = DefWindowProcA(hwnd, message, wParam, lParam);
1039     defwndproc_counter--;
1040
1041     return ret;
1042 }
1043
1044 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1045 {
1046     static long defwndproc_counter = 0;
1047     LRESULT ret;
1048     struct message msg;
1049
1050     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1051
1052     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
1053     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
1054     if (after_end_dialog)
1055         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
1056     else
1057         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
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     defwndproc_counter++;
1067     ret = DefDlgProcA(hwnd, message, wParam, lParam);
1068     defwndproc_counter--;
1069
1070     return ret;
1071 }
1072
1073 static BOOL RegisterWindowClasses(void)
1074 {
1075     WNDCLASSA cls;
1076
1077     cls.style = 0;
1078     cls.lpfnWndProc = MsgCheckProcA;
1079     cls.cbClsExtra = 0;
1080     cls.cbWndExtra = 0;
1081     cls.hInstance = GetModuleHandleA(0);
1082     cls.hIcon = 0;
1083     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1084     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1085     cls.lpszMenuName = NULL;
1086     cls.lpszClassName = "TestWindowClass";
1087     if(!RegisterClassA(&cls)) return FALSE;
1088
1089     cls.lpfnWndProc = PopupMsgCheckProcA;
1090     cls.lpszClassName = "TestPopupClass";
1091     if(!RegisterClassA(&cls)) return FALSE;
1092
1093     cls.lpfnWndProc = ParentMsgCheckProcA;
1094     cls.lpszClassName = "TestParentClass";
1095     if(!RegisterClassA(&cls)) return FALSE;
1096
1097     cls.lpfnWndProc = DefWindowProcA;
1098     cls.lpszClassName = "SimpleWindowClass";
1099     if(!RegisterClassA(&cls)) return FALSE;
1100
1101     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
1102     cls.lpfnWndProc = TestDlgProcA;
1103     cls.lpszClassName = "TestDialogClass";
1104     if(!RegisterClassA(&cls)) return FALSE;
1105
1106     return TRUE;
1107 }
1108
1109 static HHOOK hCBT_hook;
1110
1111 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
1112
1113     char buf[256];
1114
1115     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
1116
1117     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
1118     {
1119         if (!strcmp(buf, "TestWindowClass") ||
1120             !strcmp(buf, "TestParentClass") ||
1121             !strcmp(buf, "TestPopupClass") ||
1122             !strcmp(buf, "SimpleWindowClass") ||
1123             !strcmp(buf, "TestDialogClass") ||
1124             !strcmp(buf, "#32770"))
1125         {
1126             struct message msg;
1127
1128             msg.message = nCode;
1129             msg.flags = hook;
1130             msg.wParam = wParam;
1131             msg.lParam = lParam;
1132             add_message(&msg);
1133         }
1134     }
1135     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
1136 }
1137
1138 START_TEST(msg)
1139 {
1140     if (!RegisterWindowClasses()) assert(0);
1141
1142     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
1143     assert(hCBT_hook);
1144
1145     test_messages();
1146
1147     UnhookWindowsHookEx(hCBT_hook);
1148 }