Add dialog class name to the list of classes handled by hook, add hook
[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 int after_end_dialog;
603 static int sequence_cnt, sequence_size;
604 static struct message* sequence;
605
606 static void add_message(const struct message *msg)
607 {
608     if (!sequence) 
609     {
610         sequence_size = 10;
611         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
612     }
613     if (sequence_cnt == sequence_size) 
614     {
615         sequence_size *= 2;
616         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
617     }
618     assert(sequence);
619
620     sequence[sequence_cnt].message = msg->message;
621     sequence[sequence_cnt].flags = msg->flags;
622     sequence[sequence_cnt].wParam = msg->wParam;
623     sequence[sequence_cnt].lParam = msg->lParam;
624
625     sequence_cnt++;
626 }
627
628 static void flush_sequence()
629 {
630     HeapFree(GetProcessHeap(), 0, sequence);
631     sequence = 0;
632     sequence_cnt = sequence_size = 0;
633 }
634
635 static void ok_sequence(const struct message *expected, const char *context)
636 {
637     static const struct message end_of_sequence = { 0, 0, 0, 0 };
638     const struct message *actual;
639     
640     add_message(&end_of_sequence);
641
642     actual = sequence;
643
644     while (expected->message && actual->message)
645     {
646         trace("expected %04x - actual %04x\n", expected->message, actual->message);
647
648         if (expected->message == actual->message)
649         {
650             if (expected->flags & wparam)
651                  ok (expected->wParam == actual->wParam,
652                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
653                      context, expected->message, expected->wParam, actual->wParam);
654             if (expected->flags & lparam)
655                  ok (expected->lParam == actual->lParam,
656                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
657                      context, expected->message, expected->lParam, actual->lParam);
658             ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
659                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
660                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
661             ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
662                 "%s: the msg 0x%04x should have been %s\n",
663                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
664             ok ((expected->flags & parent) == (actual->flags & parent),
665                 "%s: the msg 0x%04x was expected in %s\n",
666                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
667             ok ((expected->flags & hook) == (actual->flags & hook),
668                 "%s: the msg 0x%04x should have been sent by a hook\n",
669                 context, expected->message);
670             expected++;
671             actual++;
672         }
673         else if (expected->flags & optional)
674             expected++;
675         else
676         {
677           todo_wine {
678             ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
679                 context, expected->message, actual->message);
680             expected++;
681             actual++;
682           }
683         }
684     }
685
686     /* skip all optional trailing messages */
687     while (expected->message && (expected->flags & optional))
688         expected++;
689
690   todo_wine {
691     if (expected->message || actual->message)
692         ok (FALSE, "%s: the msg sequence is not complete (got 0x%04x)\n", context, actual->message);
693   }
694
695     flush_sequence();
696 }
697
698 static void test_WM_SETREDRAW(HWND hwnd)
699 {
700     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
701
702     flush_sequence();
703
704     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
705     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE");
706
707     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
708     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
709
710     flush_sequence();
711     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
712     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE");
713
714     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
715     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
716
717     /* restore original WS_VISIBLE state */
718     SetWindowLongA(hwnd, GWL_STYLE, style);
719
720     flush_sequence();
721 }
722
723 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
724 {
725     struct message msg;
726
727     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
728
729     msg.message = message;
730     msg.flags = sent|wparam|lparam;
731     msg.wParam = wParam;
732     msg.lParam = lParam;
733     add_message(&msg);
734
735     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
736     if (message == WM_TIMER) EndDialog( hwnd, 0 );
737     return 0;
738 }
739
740 /* test if we receive the right sequence of messages */
741 static void test_messages(void)
742 {
743     HWND hwnd, hparent, hchild;
744     HWND hchild2, hbutton;
745     HMENU hmenu;
746
747     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
748                            100, 100, 200, 200, 0, 0, 0, NULL);
749     ok (hwnd != 0, "Failed to create overlapped window\n");
750     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
751
752     /* test WM_SETREDRAW on a not visible top level window */
753     test_WM_SETREDRAW(hwnd);
754
755     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
756     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped");
757     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
758
759     ok(GetActiveWindow() == hwnd, "window should be active\n");
760     ok(GetFocus() == hwnd, "window should have input focus\n");
761     ShowWindow(hwnd, SW_HIDE);
762     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped");
763     
764     ShowWindow(hwnd, SW_SHOW);
765     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped");
766
767     ok(GetActiveWindow() == hwnd, "window should be active\n");
768     ok(GetFocus() == hwnd, "window should have input focus\n");
769     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
770     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped");
771     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
772
773     /* test WM_SETREDRAW on a visible top level window */
774     ShowWindow(hwnd, SW_SHOW);
775     test_WM_SETREDRAW(hwnd);
776
777     DestroyWindow(hwnd);
778     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped");
779
780     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
781                               100, 100, 200, 200, 0, 0, 0, NULL);
782     ok (hparent != 0, "Failed to create parent window\n");
783     flush_sequence();
784
785     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
786                              0, 0, 10, 10, hparent, 0, 0, NULL);
787     ok (hchild != 0, "Failed to create child window\n");
788     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child");
789     DestroyWindow(hchild);
790     flush_sequence();
791
792     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW,
793                              0, 0, 10, 10, hparent, 0, 0, NULL);
794     ok (hchild != 0, "Failed to create child window\n");
795     ok_sequence(WmCreateChildSeq, "CreateWindow:child");
796     
797     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILDWINDOW,
798                                100, 100, 50, 50, hparent, 0, 0, NULL);
799     ok (hchild2 != 0, "Failed to create child2 window\n");
800     flush_sequence();
801
802     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILDWINDOW,
803                               0, 100, 50, 50, hchild, 0, 0, NULL);
804     ok (hbutton != 0, "Failed to create button window\n");
805
806     /* test WM_SETREDRAW on a not visible child window */
807     test_WM_SETREDRAW(hchild);
808
809     ShowWindow(hchild, SW_SHOW);
810     ok_sequence(WmShowChildSeq, "ShowWindow:child");
811
812     /* test WM_SETREDRAW on a visible child window */
813     test_WM_SETREDRAW(hchild);
814
815     SetFocus(hchild);
816     flush_sequence();
817
818     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
819     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child");
820
821     DestroyWindow(hchild);
822     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child");
823     DestroyWindow(hchild2);
824     DestroyWindow(hbutton);
825
826     flush_sequence();
827     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
828                              0, 0, 100, 100, hparent, 0, 0, NULL);
829     ok (hchild != 0, "Failed to create child popup window\n");
830     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup");
831     DestroyWindow(hchild);
832
833     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
834     flush_sequence();
835     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
836                              0, 0, 100, 100, hparent, 0, 0, NULL);
837     ok (hchild != 0, "Failed to create popup window\n");
838     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
839     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
840     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
841     flush_sequence();
842     ShowWindow(hchild, SW_SHOW);
843     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
844     flush_sequence();
845     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
846     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
847     flush_sequence();
848     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
849     ok_sequence(WmShowVisiblePopupSeq_3, "CreateWindow:show_visible_popup_3");
850     DestroyWindow(hchild);
851
852     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
853      * changes nothing in message sequences.
854      */
855     flush_sequence();
856     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
857                              0, 0, 100, 100, hparent, 0, 0, NULL);
858     ok (hchild != 0, "Failed to create popup window\n");
859     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
860     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
861     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
862     flush_sequence();
863     ShowWindow(hchild, SW_SHOW);
864     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
865     flush_sequence();
866     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
867     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
868     DestroyWindow(hchild);
869
870     flush_sequence();
871     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
872                            0, 0, 100, 100, hparent, 0, 0, NULL);
873     ok(hwnd != 0, "Failed to create custom dialog window\n");
874     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog");
875
876     flush_sequence();
877     after_end_dialog = 1;
878     EndDialog( hwnd, 0 );
879     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog");
880
881     DestroyWindow(hwnd);
882     after_end_dialog = 0;
883
884     flush_sequence();
885     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
886     ok_sequence(WmModalDialogSeq, "ModalDialog");
887
888     DestroyWindow(hparent);
889     flush_sequence();
890
891     /* Message sequence for SetMenu */
892     hmenu = CreateMenu();
893     ok (hmenu != 0, "Failed to create menu\n");
894     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
895     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
896                            100, 100, 200, 200, 0, hmenu, 0, NULL);
897     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
898     ok (SetMenu(hwnd, 0), "SetMenu\n");
899     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange");
900     ok (SetMenu(hwnd, 0), "SetMenu\n");
901     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange");
902     ShowWindow(hwnd, SW_SHOW);
903     flush_sequence();
904     ok (SetMenu(hwnd, 0), "SetMenu\n");
905     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange");
906     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
907     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange");
908
909     ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
910     ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar");
911
912     DestroyWindow(hwnd);
913 }
914
915 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
916 {
917     static long defwndproc_counter = 0;
918     LRESULT ret;
919     struct message msg;
920
921     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
922
923     msg.message = message;
924     msg.flags = sent|wparam|lparam;
925     if (defwndproc_counter) msg.flags |= defwinproc;
926     msg.wParam = wParam;
927     msg.lParam = lParam;
928     add_message(&msg);
929
930     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
931     {
932         HWND parent = GetParent(hwnd);
933         RECT rc;
934         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
935
936         GetClientRect(parent, &rc);
937         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
938
939         trace("ptReserved = (%ld,%ld)\n"
940               "ptMaxSize = (%ld,%ld)\n"
941               "ptMaxPosition = (%ld,%ld)\n"
942               "ptMinTrackSize = (%ld,%ld)\n"
943               "ptMaxTrackSize = (%ld,%ld)\n",
944               minmax->ptReserved.x, minmax->ptReserved.y,
945               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
946               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
947               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
948               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
949
950         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
951            minmax->ptMaxSize.x, rc.right);
952         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
953            minmax->ptMaxSize.y, rc.bottom);
954     }
955
956     defwndproc_counter++;
957     ret = DefWindowProcA(hwnd, message, wParam, lParam);
958     defwndproc_counter--;
959
960     return ret;
961 }
962
963 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
964 {
965     static long defwndproc_counter = 0;
966     LRESULT ret;
967     struct message msg;
968
969     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
970
971     msg.message = message;
972     msg.flags = sent|wparam|lparam;
973     if (defwndproc_counter) msg.flags |= defwinproc;
974     msg.wParam = wParam;
975     msg.lParam = lParam;
976     add_message(&msg);
977
978     if (message == WM_CREATE)
979     {
980         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
981         SetWindowLongA(hwnd, GWL_STYLE, style);
982     }
983
984     defwndproc_counter++;
985     ret = DefWindowProcA(hwnd, message, wParam, lParam);
986     defwndproc_counter--;
987
988     return ret;
989 }
990
991 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
992 {
993     static long defwndproc_counter = 0;
994     LRESULT ret;
995     struct message msg;
996
997     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
998
999     if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
1000         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
1001         message == WM_ENABLE || message == WM_ENTERIDLE ||
1002         message == WM_IME_SETCONTEXT)
1003     {
1004         msg.message = message;
1005         msg.flags = sent|parent|wparam|lparam;
1006         if (defwndproc_counter) msg.flags |= defwinproc;
1007         msg.wParam = wParam;
1008         msg.lParam = lParam;
1009         add_message(&msg);
1010     }
1011
1012     defwndproc_counter++;
1013     ret = DefWindowProcA(hwnd, message, wParam, lParam);
1014     defwndproc_counter--;
1015
1016     return ret;
1017 }
1018
1019 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1020 {
1021     static long defwndproc_counter = 0;
1022     LRESULT ret;
1023     struct message msg;
1024
1025     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1026
1027     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
1028     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
1029     if (after_end_dialog)
1030         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
1031     else
1032         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
1033
1034     msg.message = message;
1035     msg.flags = sent|wparam|lparam;
1036     if (defwndproc_counter) msg.flags |= defwinproc;
1037     msg.wParam = wParam;
1038     msg.lParam = lParam;
1039     add_message(&msg);
1040
1041     defwndproc_counter++;
1042     ret = DefDlgProcA(hwnd, message, wParam, lParam);
1043     defwndproc_counter--;
1044
1045     return ret;
1046 }
1047
1048 static BOOL RegisterWindowClasses(void)
1049 {
1050     WNDCLASSA cls;
1051
1052     cls.style = 0;
1053     cls.lpfnWndProc = MsgCheckProcA;
1054     cls.cbClsExtra = 0;
1055     cls.cbWndExtra = 0;
1056     cls.hInstance = GetModuleHandleA(0);
1057     cls.hIcon = 0;
1058     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1059     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1060     cls.lpszMenuName = NULL;
1061     cls.lpszClassName = "TestWindowClass";
1062     if(!RegisterClassA(&cls)) return FALSE;
1063
1064     cls.lpfnWndProc = PopupMsgCheckProcA;
1065     cls.lpszClassName = "TestPopupClass";
1066     if(!RegisterClassA(&cls)) return FALSE;
1067
1068     cls.lpfnWndProc = ParentMsgCheckProcA;
1069     cls.lpszClassName = "TestParentClass";
1070     if(!RegisterClassA(&cls)) return FALSE;
1071
1072     cls.lpfnWndProc = DefWindowProcA;
1073     cls.lpszClassName = "SimpleWindowClass";
1074     if(!RegisterClassA(&cls)) return FALSE;
1075
1076     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
1077     cls.lpfnWndProc = TestDlgProcA;
1078     cls.lpszClassName = "TestDialogClass";
1079     if(!RegisterClassA(&cls)) return FALSE;
1080
1081     return TRUE;
1082 }
1083
1084 static HHOOK hCBT_hook;
1085
1086 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
1087
1088     char buf[256];
1089
1090     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
1091
1092     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
1093     {
1094         if (!strcmp(buf, "TestWindowClass") ||
1095             !strcmp(buf, "TestParentClass") ||
1096             !strcmp(buf, "TestPopupClass") ||
1097             !strcmp(buf, "SimpleWindowClass") ||
1098             !strcmp(buf, "TestDialogClass") ||
1099             !strcmp(buf, "#32770"))
1100         {
1101             struct message msg;
1102
1103             msg.message = nCode;
1104             msg.flags = hook;
1105             msg.wParam = wParam;
1106             msg.lParam = lParam;
1107             add_message(&msg);
1108         }
1109     }
1110     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
1111 }
1112
1113 START_TEST(msg)
1114 {
1115     if (!RegisterWindowClasses()) assert(0);
1116
1117     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
1118     assert(hCBT_hook);
1119
1120     test_messages();
1121
1122     UnhookWindowsHookEx(hCBT_hook);
1123 }