- Make new tests pass on win2k SP4 and win95 OSR2.
[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     { WM_SETFONT, sent },
441     { WM_INITDIALOG, sent },
442     { WM_CHANGEUISTATE, sent|optional },
443     { WM_SHOWWINDOW, sent },
444     { WM_WINDOWPOSCHANGING, sent },
445     { WM_NCACTIVATE, sent|wparam, 1 },
446     { WM_GETICON, sent|optional },
447     { WM_GETICON, sent|optional },
448     { WM_GETICON, sent|optional },
449     { WM_GETTEXT, sent|optional },
450     { WM_ACTIVATE, sent|wparam, 1 },
451     { WM_WINDOWPOSCHANGING, sent },
452     { WM_NCPAINT, sent },
453     { WM_GETICON, sent|optional },
454     { WM_GETICON, sent|optional },
455     { WM_GETICON, sent|optional },
456     { WM_GETTEXT, sent|optional },
457     { WM_ERASEBKGND, sent },
458     { WM_CTLCOLORDLG, sent },
459     { WM_WINDOWPOSCHANGED, sent },
460     { WM_GETICON, sent|optional },
461     { WM_GETICON, sent|optional },
462     { WM_GETICON, sent|optional },
463     { WM_GETTEXT, sent|optional },
464     { WM_NCCALCSIZE, sent|optional },
465     { WM_NCPAINT, sent|optional },
466     { WM_GETICON, sent|optional },
467     { WM_GETICON, sent|optional },
468     { WM_GETICON, sent|optional },
469     { WM_GETTEXT, sent|optional },
470     { WM_ERASEBKGND, sent|optional },
471     { WM_CTLCOLORDLG, sent|optional },
472     { WM_PAINT, sent|optional },
473     { WM_CTLCOLORBTN, sent },
474     { WM_ENTERIDLE, sent|parent },
475     { WM_TIMER, sent },
476     { WM_ENABLE, sent|parent|wparam, 1 },
477     { WM_WINDOWPOSCHANGING, sent },
478     { WM_WINDOWPOSCHANGED, sent },
479     { WM_GETICON, sent|optional },
480     { WM_GETICON, sent|optional },
481     { WM_GETICON, sent|optional },
482     { WM_GETTEXT, sent|optional },
483     { HCBT_ACTIVATE, hook },
484     { WM_NCACTIVATE, sent|wparam, 0 },
485     { WM_GETICON, sent|optional },
486     { WM_GETICON, sent|optional },
487     { WM_GETICON, sent|optional },
488     { WM_GETTEXT, sent|optional },
489     { WM_ACTIVATE, sent|wparam, 0 },
490     { WM_WINDOWPOSCHANGING, sent|optional },
491     { HCBT_SETFOCUS, hook },
492     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
493     { WM_SETFOCUS, sent|parent|defwinproc },
494     { WM_DESTROY, sent },
495     { WM_NCDESTROY, sent },
496     { 0 }
497 };
498 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
499 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
500     /* (inside dialog proc, handling WM_INITDIALOG) */
501     { WM_WINDOWPOSCHANGING, sent },
502     { WM_NCCALCSIZE, sent },
503     { WM_NCACTIVATE, sent|parent|wparam, 0 },
504     { WM_GETTEXT, sent|defwinproc },
505     { WM_ACTIVATE, sent|parent|wparam, 0 },
506     { WM_WINDOWPOSCHANGING, sent },
507     { WM_WINDOWPOSCHANGING, sent|parent },
508     { WM_NCACTIVATE, sent|wparam, 1 },
509     { WM_ACTIVATE, sent|wparam, 1 },
510     { WM_WINDOWPOSCHANGED, sent },
511     { WM_SIZE, sent|defwinproc },
512     /* (setting focus) */
513     { WM_SHOWWINDOW, sent|wparam, 1 },
514     { WM_WINDOWPOSCHANGING, sent },
515     { WM_NCPAINT, sent },
516     { WM_GETTEXT, sent|defwinproc },
517     { WM_ERASEBKGND, sent },
518     { WM_CTLCOLORDLG, sent|defwinproc },
519     { WM_WINDOWPOSCHANGED, sent },
520     { WM_PAINT, sent },
521     /* (bunch of WM_CTLCOLOR* for each control) */
522     { WM_PAINT, sent|parent },
523     { WM_ENTERIDLE, sent|parent|wparam, 0 },
524     { WM_SETCURSOR, sent|parent },
525     { 0 }
526 };
527 /* SetMenu for NonVisible windows with size change*/
528 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
529     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
530     { WM_NCCALCSIZE, sent|wparam, 1 },
531     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
532     { WM_MOVE, sent|defwinproc },
533     { WM_SIZE, sent|defwinproc },
534     { WM_GETICON, sent|optional },
535     { WM_GETICON, sent|optional },
536     { WM_GETICON, sent|optional },
537     { WM_GETTEXT, sent|optional },
538     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
539     { 0 }
540 };
541 /* SetMenu for NonVisible windows with no size change */
542 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
543     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
544     { WM_NCCALCSIZE, sent|wparam, 1 },
545     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
546     { 0 }
547 };
548 /* SetMenu for Visible windows with size change */
549 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
550     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
551     { WM_NCCALCSIZE, sent|wparam, 1 },
552     { WM_NCPAINT, sent|wparam, 1 },
553     { WM_GETTEXT, sent|defwinproc|optional },
554     { WM_ERASEBKGND, sent|optional },
555     { WM_ACTIVATE, sent|optional },
556     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
557     { WM_MOVE, sent|defwinproc },
558     { WM_SIZE, sent|defwinproc },
559     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
560     { WM_NCPAINT, sent|wparam|optional, 1 },
561     { WM_ERASEBKGND, sent|optional },
562     { 0 }
563 };
564 /* SetMenu for Visible windows with no size change */
565 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
566     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
567     { WM_NCCALCSIZE, sent|wparam, 1 },
568     { WM_NCPAINT, sent|wparam, 1 },
569     { WM_GETTEXT, sent|defwinproc|optional },
570     { WM_ERASEBKGND, sent|optional },
571     { WM_ACTIVATE, sent|optional },
572     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
573     { 0 }
574 };
575
576 static const struct message WmSetRedrawFalseSeq[] =
577 {
578     { WM_SETREDRAW, sent|wparam, 0 },
579     { 0 }
580 };
581
582 static const struct message WmSetRedrawTrueSeq[] =
583 {
584     { WM_SETREDRAW, sent|wparam, 1 },
585     { 0 }
586 };
587
588 static int after_end_dialog;
589 static int sequence_cnt, sequence_size;
590 static struct message* sequence;
591
592 static void add_message(const struct message *msg)
593 {
594     if (!sequence) 
595     {
596         sequence_size = 10;
597         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
598     }
599     if (sequence_cnt == sequence_size) 
600     {
601         sequence_size *= 2;
602         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
603     }
604     assert(sequence);
605
606     sequence[sequence_cnt].message = msg->message;
607     sequence[sequence_cnt].flags = msg->flags;
608     sequence[sequence_cnt].wParam = msg->wParam;
609     sequence[sequence_cnt].lParam = msg->lParam;
610
611     sequence_cnt++;
612 }
613
614 static void flush_sequence()
615 {
616     HeapFree(GetProcessHeap(), 0, sequence);
617     sequence = 0;
618     sequence_cnt = sequence_size = 0;
619 }
620
621 static void ok_sequence(const struct message *expected, const char *context)
622 {
623     static const struct message end_of_sequence = { 0, 0, 0, 0 };
624     const struct message *actual;
625     
626     add_message(&end_of_sequence);
627
628     actual = sequence;
629
630     while (expected->message && actual->message)
631     {
632         trace("expected %04x - actual %04x\n", expected->message, actual->message);
633
634         if (expected->message == actual->message)
635         {
636             if (expected->flags & wparam)
637                  ok (expected->wParam == actual->wParam,
638                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
639                      context, expected->message, expected->wParam, actual->wParam);
640             if (expected->flags & lparam)
641                  ok (expected->lParam == actual->lParam,
642                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
643                      context, expected->message, expected->lParam, actual->lParam);
644             ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
645                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
646                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
647             ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
648                 "%s: the msg 0x%04x should have been %s\n",
649                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
650             ok ((expected->flags & parent) == (actual->flags & parent),
651                 "%s: the msg 0x%04x was expected in %s\n",
652                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
653             ok ((expected->flags & hook) == (actual->flags & hook),
654                 "%s: the msg 0x%04x should have been sent by a hook\n",
655                 context, expected->message);
656             expected++;
657             actual++;
658         }
659         else if (expected->flags & optional)
660             expected++;
661         else
662         {
663           todo_wine {
664             ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
665                 context, expected->message, actual->message);
666             expected++;
667             actual++;
668           }
669         }
670     }
671
672     /* skip all optional trailing messages */
673     while (expected->message && (expected->flags & optional))
674         expected++;
675
676   todo_wine {
677     if (expected->message || actual->message)
678         ok (FALSE, "%s: the msg sequence is not complete (got 0x%04x)\n", context, actual->message);
679   }
680
681     flush_sequence();
682 }
683
684 static void test_WM_SETREDRAW(HWND hwnd)
685 {
686     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
687
688     flush_sequence();
689
690     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
691     ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE");
692
693     ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
694     ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
695
696     flush_sequence();
697     SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
698     ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE");
699
700     ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
701     ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
702
703     /* restore original WS_VISIBLE state */
704     SetWindowLongA(hwnd, GWL_STYLE, style);
705
706     flush_sequence();
707 }
708
709 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
710 {
711     struct message msg;
712
713     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
714
715     msg.message = message;
716     msg.flags = sent|wparam|lparam;
717     msg.wParam = wParam;
718     msg.lParam = lParam;
719     add_message(&msg);
720
721     if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
722     if (message == WM_TIMER) EndDialog( hwnd, 0 );
723     return 0;
724 }
725
726 /* test if we receive the right sequence of messages */
727 static void test_messages(void)
728 {
729     HWND hwnd, hparent, hchild;
730     HWND hchild2, hbutton;
731     HMENU hmenu;
732
733     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
734                            100, 100, 200, 200, 0, 0, 0, NULL);
735     ok (hwnd != 0, "Failed to create overlapped window\n");
736     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
737
738     /* test WM_SETREDRAW on a not visible top level window */
739     test_WM_SETREDRAW(hwnd);
740
741     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
742     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped");
743     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
744
745     ok(GetActiveWindow() == hwnd, "window should be active\n");
746     ok(GetFocus() == hwnd, "window should have input focus\n");
747     ShowWindow(hwnd, SW_HIDE);
748     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped");
749     
750     ShowWindow(hwnd, SW_SHOW);
751     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped");
752
753     ok(GetActiveWindow() == hwnd, "window should be active\n");
754     ok(GetFocus() == hwnd, "window should have input focus\n");
755     SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
756     ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped");
757     ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
758
759     /* test WM_SETREDRAW on a visible top level window */
760     ShowWindow(hwnd, SW_SHOW);
761     test_WM_SETREDRAW(hwnd);
762
763     DestroyWindow(hwnd);
764     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped");
765
766     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
767                               100, 100, 200, 200, 0, 0, 0, NULL);
768     ok (hparent != 0, "Failed to create parent window\n");
769     flush_sequence();
770
771     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
772                              0, 0, 10, 10, hparent, 0, 0, NULL);
773     ok (hchild != 0, "Failed to create child window\n");
774     ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child");
775     DestroyWindow(hchild);
776     flush_sequence();
777
778     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW,
779                              0, 0, 10, 10, hparent, 0, 0, NULL);
780     ok (hchild != 0, "Failed to create child window\n");
781     ok_sequence(WmCreateChildSeq, "CreateWindow:child");
782     
783     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILDWINDOW,
784                                100, 100, 50, 50, hparent, 0, 0, NULL);
785     ok (hchild2 != 0, "Failed to create child2 window\n");
786     flush_sequence();
787
788     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILDWINDOW,
789                               0, 100, 50, 50, hchild, 0, 0, NULL);
790     ok (hbutton != 0, "Failed to create button window\n");
791
792     /* test WM_SETREDRAW on a not visible child window */
793     test_WM_SETREDRAW(hchild);
794
795     ShowWindow(hchild, SW_SHOW);
796     ok_sequence(WmShowChildSeq, "ShowWindow:child");
797
798     /* test WM_SETREDRAW on a visible child window */
799     test_WM_SETREDRAW(hchild);
800
801     SetFocus(hchild);
802     flush_sequence();
803
804     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
805     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child");
806
807     DestroyWindow(hchild);
808     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child");
809     DestroyWindow(hchild2);
810     DestroyWindow(hbutton);
811
812     flush_sequence();
813     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
814                              0, 0, 100, 100, hparent, 0, 0, NULL);
815     ok (hchild != 0, "Failed to create child popup window\n");
816     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup");
817     DestroyWindow(hchild);
818
819     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
820     flush_sequence();
821     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
822                              0, 0, 100, 100, hparent, 0, 0, NULL);
823     ok (hchild != 0, "Failed to create popup window\n");
824     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
825     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
826     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
827     flush_sequence();
828     ShowWindow(hchild, SW_SHOW);
829     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
830     flush_sequence();
831     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
832     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
833     flush_sequence();
834     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
835     ok_sequence(WmShowVisiblePopupSeq_3, "CreateWindow:show_visible_popup_3");
836     DestroyWindow(hchild);
837
838     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
839      * changes nothing in message sequences.
840      */
841     flush_sequence();
842     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
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     DestroyWindow(hchild);
855
856     flush_sequence();
857     hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
858                            0, 0, 100, 100, hparent, 0, 0, NULL);
859     ok(hwnd != 0, "Failed to create custom dialog window\n");
860     ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog");
861
862     flush_sequence();
863     after_end_dialog = 1;
864     EndDialog( hwnd, 0 );
865     ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog");
866
867     DestroyWindow(hwnd);
868     after_end_dialog = 0;
869
870     flush_sequence();
871     DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
872     ok_sequence(WmModalDialogSeq, "ModalDialog");
873
874     DestroyWindow(hparent);
875     flush_sequence();
876
877     /* Message sequence for SetMenu */
878     hmenu = CreateMenu();
879     ok (hmenu != 0, "Failed to create menu\n");
880     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
881     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
882                            100, 100, 200, 200, 0, hmenu, 0, NULL);
883     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
884     ok (SetMenu(hwnd, 0), "SetMenu\n");
885     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange");
886     ok (SetMenu(hwnd, 0), "SetMenu\n");
887     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange");
888     ShowWindow(hwnd, SW_SHOW);
889     flush_sequence();
890     ok (SetMenu(hwnd, 0), "SetMenu\n");
891     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange");
892     ok (SetMenu(hwnd, hmenu), "SetMenu\n");
893     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange");
894
895     DestroyWindow(hwnd);
896 }
897
898 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
899 {
900     static long defwndproc_counter = 0;
901     LRESULT ret;
902     struct message msg;
903
904     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
905
906     msg.message = message;
907     msg.flags = sent|wparam|lparam;
908     if (defwndproc_counter) msg.flags |= defwinproc;
909     msg.wParam = wParam;
910     msg.lParam = lParam;
911     add_message(&msg);
912
913     if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
914     {
915         HWND parent = GetParent(hwnd);
916         RECT rc;
917         MINMAXINFO *minmax = (MINMAXINFO *)lParam;
918
919         GetClientRect(parent, &rc);
920         trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
921
922         trace("ptReserved = (%ld,%ld)\n"
923               "ptMaxSize = (%ld,%ld)\n"
924               "ptMaxPosition = (%ld,%ld)\n"
925               "ptMinTrackSize = (%ld,%ld)\n"
926               "ptMaxTrackSize = (%ld,%ld)\n",
927               minmax->ptReserved.x, minmax->ptReserved.y,
928               minmax->ptMaxSize.x, minmax->ptMaxSize.y,
929               minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
930               minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
931               minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
932
933         ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
934            minmax->ptMaxSize.x, rc.right);
935         ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
936            minmax->ptMaxSize.y, rc.bottom);
937     }
938
939     defwndproc_counter++;
940     ret = DefWindowProcA(hwnd, message, wParam, lParam);
941     defwndproc_counter--;
942
943     return ret;
944 }
945
946 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
947 {
948     static long defwndproc_counter = 0;
949     LRESULT ret;
950     struct message msg;
951
952     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
953
954     msg.message = message;
955     msg.flags = sent|wparam|lparam;
956     if (defwndproc_counter) msg.flags |= defwinproc;
957     msg.wParam = wParam;
958     msg.lParam = lParam;
959     add_message(&msg);
960
961     if (message == WM_CREATE)
962     {
963         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
964         SetWindowLongA(hwnd, GWL_STYLE, style);
965     }
966
967     defwndproc_counter++;
968     ret = DefWindowProcA(hwnd, message, wParam, lParam);
969     defwndproc_counter--;
970
971     return ret;
972 }
973
974 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
975 {
976     static long defwndproc_counter = 0;
977     LRESULT ret;
978     struct message msg;
979
980     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
981
982     if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
983         message == WM_SETFOCUS || message == WM_KILLFOCUS ||
984         message == WM_ENABLE || message == WM_ENTERIDLE ||
985         message == WM_IME_SETCONTEXT)
986     {
987         msg.message = message;
988         msg.flags = sent|parent|wparam|lparam;
989         if (defwndproc_counter) msg.flags |= defwinproc;
990         msg.wParam = wParam;
991         msg.lParam = lParam;
992         add_message(&msg);
993     }
994
995     defwndproc_counter++;
996     ret = DefWindowProcA(hwnd, message, wParam, lParam);
997     defwndproc_counter--;
998
999     return ret;
1000 }
1001
1002 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1003 {
1004     static long defwndproc_counter = 0;
1005     LRESULT ret;
1006     struct message msg;
1007
1008     trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
1009
1010     DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
1011     ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
1012     if (after_end_dialog)
1013         ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
1014     else
1015         ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
1016
1017     msg.message = message;
1018     msg.flags = sent|wparam|lparam;
1019     if (defwndproc_counter) msg.flags |= defwinproc;
1020     msg.wParam = wParam;
1021     msg.lParam = lParam;
1022     add_message(&msg);
1023
1024     defwndproc_counter++;
1025     ret = DefDlgProcA(hwnd, message, wParam, lParam);
1026     defwndproc_counter--;
1027
1028     return ret;
1029 }
1030
1031 static BOOL RegisterWindowClasses(void)
1032 {
1033     WNDCLASSA cls;
1034
1035     cls.style = 0;
1036     cls.lpfnWndProc = MsgCheckProcA;
1037     cls.cbClsExtra = 0;
1038     cls.cbWndExtra = 0;
1039     cls.hInstance = GetModuleHandleA(0);
1040     cls.hIcon = 0;
1041     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1042     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1043     cls.lpszMenuName = NULL;
1044     cls.lpszClassName = "TestWindowClass";
1045     if(!RegisterClassA(&cls)) return FALSE;
1046
1047     cls.lpfnWndProc = PopupMsgCheckProcA;
1048     cls.lpszClassName = "TestPopupClass";
1049     if(!RegisterClassA(&cls)) return FALSE;
1050
1051     cls.lpfnWndProc = ParentMsgCheckProcA;
1052     cls.lpszClassName = "TestParentClass";
1053     if(!RegisterClassA(&cls)) return FALSE;
1054
1055     cls.lpfnWndProc = DefWindowProcA;
1056     cls.lpszClassName = "SimpleWindowClass";
1057     if(!RegisterClassA(&cls)) return FALSE;
1058
1059     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
1060     cls.lpfnWndProc = TestDlgProcA;
1061     cls.lpszClassName = "TestDialogClass";
1062     if(!RegisterClassA(&cls)) return FALSE;
1063
1064     return TRUE;
1065 }
1066
1067 static HHOOK hCBT_hook;
1068
1069 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
1070
1071     char buf[256];
1072
1073     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
1074
1075     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
1076     {
1077         if (!strcmp(buf, "TestWindowClass") ||
1078             !strcmp(buf, "TestParentClass") ||
1079             !strcmp(buf, "TestPopupClass") ||
1080             !strcmp(buf, "SimpleWindowClass") ||
1081             !strcmp(buf, "TestDialogClass"))
1082         {
1083             struct message msg;
1084
1085             msg.message = nCode;
1086             msg.flags = hook;
1087             msg.wParam = wParam;
1088             msg.lParam = lParam;
1089             add_message(&msg);
1090         }
1091     }
1092     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
1093 }
1094
1095 START_TEST(msg)
1096 {
1097     if (!RegisterWindowClasses()) assert(0);
1098
1099     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
1100     assert(hCBT_hook);
1101
1102     test_messages();
1103
1104     UnhookWindowsHookEx(hCBT_hook);
1105 }