Make use of the 'defwinproc' flag in the message test.
[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 /* ShowWindow (for overlapped window) (16/32) */
66 static const struct message WmShowOverlappedSeq[] = {
67     { WM_SHOWWINDOW, sent|wparam, 1 },
68     { WM_NCPAINT, sent|wparam|optional, 1 },
69     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
70     /* FIXME: WM_QUERYNEWPALETTE, if in 256-color mode */
71     { WM_NCPAINT, sent|wparam|optional, 1 },
72     { WM_GETTEXT, sent|defwinproc|optional },
73     { WM_ERASEBKGND, sent|optional },
74     { HCBT_ACTIVATE, hook },
75     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
76     { WM_ACTIVATEAPP, sent|wparam, 1 },
77     { WM_NCACTIVATE, sent|wparam, 1 },
78     { WM_GETTEXT, sent|defwinproc },
79     { WM_ACTIVATE, sent|wparam, 1 },
80     { HCBT_SETFOCUS, hook },
81     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
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_SIZE, sent },
88     { WM_MOVE, sent },
89     { 0 }
90 };
91 /* DestroyWindow (for overlapped window) (32) */
92 static const struct message WmDestroyOverlappedSeq[] = {
93     { HCBT_DESTROYWND, hook },
94     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
95     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
96     { WM_NCACTIVATE, sent|wparam, 0 },
97     { WM_ACTIVATE, sent|wparam, 0 },
98     { WM_ACTIVATEAPP, sent|wparam, 0 },
99     { WM_KILLFOCUS, sent|wparam, 0 },
100     { WM_IME_SETCONTEXT, sent|optional },
101     { WM_DESTROY, sent },
102     { WM_NCDESTROY, sent },
103     { 0 }
104 };
105 /* CreateWindow (for a child popup window, not initially visible) */
106 static const struct message WmCreateChildPopupSeq[] = {
107     { HCBT_CREATEWND, hook },
108     { WM_NCCREATE, sent }, 
109     { WM_NCCALCSIZE, sent|wparam, 0 },
110     { WM_CREATE, sent },
111     { WM_SIZE, sent },
112     { WM_MOVE, sent },
113     { 0 }
114 };
115 /* CreateWindow (for a popup window, not initially visible,
116  * which sets WS_VISIBLE in WM_CREATE handler)
117  */
118 static const struct message WmCreateInvisiblePopupSeq[] = {
119     { HCBT_CREATEWND, hook },
120     { WM_NCCREATE, sent }, 
121     { WM_NCCALCSIZE, sent|wparam, 0 },
122     { WM_CREATE, sent },
123     { WM_STYLECHANGING, sent },
124     { WM_STYLECHANGED, sent },
125     { WM_SIZE, sent },
126     { WM_MOVE, sent },
127     { 0 }
128 };
129 /* ShowWindow (for a popup window with WS_VISIBLE style set) */
130 static const struct message WmShowVisiblePopupSeq[] = {
131     { 0 }
132 };
133 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
134  * for a popup window with WS_VISIBLE style set
135  */
136 static const struct message WmShowVisiblePopupSeq_2[] = {
137     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
138     { 0 }
139 };
140 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
141  * for a popup window with WS_VISIBLE style set
142  */
143 static const struct message WmShowVisiblePopupSeq_3[] = {
144     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
145     { HCBT_ACTIVATE, hook },
146     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
147     { WM_NCACTIVATE, sent|wparam, 1 },
148     { WM_ACTIVATE, sent|wparam, 1 },
149     { HCBT_SETFOCUS, hook },
150     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
151     { WM_SETFOCUS, sent|defwinproc },
152     { 0 }
153 };
154 /* CreateWindow (for child window, not initially visible) */
155 static const struct message WmCreateChildSeq[] = {
156     { HCBT_CREATEWND, hook },
157     { WM_NCCREATE, sent }, 
158     /* child is inserted into parent's child list after WM_NCCREATE returns */
159     { WM_NCCALCSIZE, sent|wparam, 0 },
160     { WM_CREATE, sent },
161     { WM_SIZE, sent },
162     { WM_MOVE, sent },
163     { WM_PARENTNOTIFY, sent|parent|wparam, 1 },
164     { 0 }
165 };
166 /* ShowWindow (for child window) */
167 static const struct message WmShowChildSeq[] = {
168     { WM_SHOWWINDOW, sent|wparam, 1 },
169     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
170     { WM_ERASEBKGND, sent|parent|optional },
171     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
172     { 0 }
173 };
174 /* DestroyWindow (for child window) */
175 static const struct message WmDestroyChildSeq[] = {
176     { HCBT_DESTROYWND, hook },
177     { WM_PARENTNOTIFY, sent|parent|wparam, 2 },
178     { WM_SHOWWINDOW, sent|wparam, 0 },
179     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
180     { WM_ERASEBKGND, sent|parent|optional },
181     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
182     { HCBT_SETFOCUS, hook }, /* set focus to a parent */
183     { WM_KILLFOCUS, sent },
184     { WM_IME_SETCONTEXT, sent|optional },
185     { WM_DESTROY, sent },
186     { WM_DESTROY, sent|optional }, /* a bug in win2k sp4 ? */
187     { WM_NCDESTROY, sent },
188     { WM_NCDESTROY, sent|optional }, /* a bug in win2k sp4 ? */
189     { 0 }
190 };
191 /* Moving the mouse in nonclient area */
192 static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
193     { WM_NCHITTEST, sent },
194     { WM_SETCURSOR, sent },
195     { WM_NCMOUSEMOVE, posted },
196     { 0 }
197 };
198 /* Moving the mouse in client area */
199 static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
200     { WM_NCHITTEST, sent },
201     { WM_SETCURSOR, sent },
202     { WM_MOUSEMOVE, posted },
203     { 0 }
204 };
205 /* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
206 static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
207     { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
208     { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
209     { WM_GETMINMAXINFO, sent|defwinproc },
210     { WM_ENTERSIZEMOVE, sent|defwinproc },
211     { WM_WINDOWPOSCHANGING, sent|defwinproc },
212     { WM_WINDOWPOSCHANGED, sent|defwinproc },
213     { WM_MOVE, sent|defwinproc },
214     { WM_EXITSIZEMOVE, sent|defwinproc },
215     { 0 }
216 };
217 /* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
218 static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
219     { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
220     { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
221     { WM_GETMINMAXINFO, sent|defwinproc },
222     { WM_ENTERSIZEMOVE, sent|defwinproc },
223     { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
224     { WM_WINDOWPOSCHANGING, sent|defwinproc },
225     { WM_GETMINMAXINFO, sent|defwinproc },
226     { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
227     { WM_NCPAINT, sent|defwinproc|wparam, 1 },
228     { WM_GETTEXT, sent|defwinproc },
229     { WM_ERASEBKGND, sent|defwinproc },
230     { WM_WINDOWPOSCHANGED, sent|defwinproc },
231     { WM_MOVE, sent|defwinproc },
232     { WM_SIZE, sent|defwinproc },
233     { WM_EXITSIZEMOVE, sent|defwinproc },
234     { 0 }
235 };
236 /* Resizing child window with MoveWindow (32) */
237 static const struct message WmResizingChildWithMoveWindowSeq[] = {
238     { WM_WINDOWPOSCHANGING, sent },
239     { WM_NCCALCSIZE, sent|wparam, 1 },
240     { WM_ERASEBKGND, sent|optional },
241     { WM_WINDOWPOSCHANGED, sent },
242     { WM_MOVE, sent|defwinproc },
243     { WM_SIZE, sent|defwinproc },
244     { 0 }
245 };
246 /* Clicking on inactive button */
247 static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
248     { WM_NCHITTEST, sent },
249     { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
250     { WM_MOUSEACTIVATE, sent },
251     { WM_MOUSEACTIVATE, sent|parent|defwinproc },
252     { WM_SETCURSOR, sent },
253     { WM_SETCURSOR, sent|parent|defwinproc },
254     { WM_LBUTTONDOWN, posted },
255     { WM_KILLFOCUS, posted|parent },
256     { WM_SETFOCUS, posted },
257     { WM_CTLCOLORBTN, posted|parent },
258     { BM_SETSTATE, posted },
259     { WM_CTLCOLORBTN, posted|parent },
260     { WM_LBUTTONUP, posted },
261     { BM_SETSTATE, posted },
262     { WM_CTLCOLORBTN, posted|parent },
263     { WM_COMMAND, posted|parent },
264     { 0 }
265 };
266 /* Reparenting a button (16/32) */
267 /* The last child (button) reparented gets topmost for its new parent. */
268 static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
269     { WM_SHOWWINDOW, sent|wparam, 0 },
270     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
271     { WM_ERASEBKGND, sent|parent },
272     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
273     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
274     { WM_CHILDACTIVATE, sent },
275     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
276     { WM_MOVE, sent|defwinproc },
277     { WM_SHOWWINDOW, sent|wparam, 1 },
278     { 0 }
279 };
280 /* Creation of a modal dialog (32) */
281 static const struct message WmCreateModalDialogSeq[] = { /* FIXME: add */
282     { WM_CANCELMODE, sent|parent },
283     { WM_KILLFOCUS, sent|parent },
284     { WM_ENABLE, sent|parent|wparam, 0 },
285     /* (window proc creation messages not tracked yet, because...) */
286     { WM_SETFONT, sent },
287     { WM_INITDIALOG, sent },
288     /* (...the window proc message hook was installed here, IsVisible still FALSE) */
289     { WM_NCACTIVATE, sent|parent|wparam, 0 },
290     { WM_GETTEXT, sent|defwinproc },
291     { WM_ACTIVATE, sent|parent|wparam, 0 },
292     { WM_WINDOWPOSCHANGING, sent },
293     { WM_WINDOWPOSCHANGING, sent|parent },
294     { WM_NCACTIVATE, sent|wparam, 1 },
295     { WM_ACTIVATE, sent|wparam, 1 },
296     /* (setting focus) */
297     { WM_SHOWWINDOW, sent|wparam, 1 },
298     { WM_WINDOWPOSCHANGING, sent },
299     { WM_NCPAINT, sent },
300     { WM_GETTEXT, sent|defwinproc },
301     { WM_ERASEBKGND, sent },
302     { WM_CTLCOLORDLG, sent|defwinproc },
303     { WM_WINDOWPOSCHANGED, sent },
304     { WM_PAINT, sent },
305     /* FIXME: (bunch of WM_CTLCOLOR* for each control) */
306     { WM_PAINT, sent|parent },
307     { WM_ENTERIDLE, sent|parent|wparam, 0},
308     { WM_SETCURSOR, sent|parent },
309     { 0 }
310 };
311 /* Destruction of a modal dialog (32) */
312 static const struct message WmDestroyModalDialogSeq[] = { /* FIXME: add */
313     /* (inside dialog proc: EndDialog is called) */
314     { WM_ENABLE, sent|parent|wparam, 1 },
315     { WM_SETFOCUS, sent },
316     { WM_WINDOWPOSCHANGING, sent },
317     { WM_NCPAINT, sent|parent },
318     { WM_GETTEXT, sent|defwinproc },
319     { WM_ERASEBKGND, sent|parent },
320     { WM_WINDOWPOSCHANGED, sent },
321     { WM_NCACTIVATE, sent|wparam, 0 },
322     { WM_ACTIVATE, sent|wparam, 0 },
323     { WM_WINDOWPOSCHANGING, sent },
324     { WM_WINDOWPOSCHANGING, sent|parent },
325     { WM_NCACTIVATE, sent|parent|wparam, 1 },
326     { WM_GETTEXT, sent|defwinproc },
327     { WM_ACTIVATE, sent|parent|wparam, 1 },
328     { WM_KILLFOCUS, sent },
329     { WM_SETFOCUS, sent|parent },
330     { WM_DESTROY, sent },
331     { WM_NCDESTROY, sent },
332     { 0 }
333 };
334 /* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
335 static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
336     /* (inside dialog proc, handling WM_INITDIALOG) */
337     { WM_WINDOWPOSCHANGING, sent },
338     { WM_NCCALCSIZE, sent },
339     { WM_NCACTIVATE, sent|parent|wparam, 0 },
340     { WM_GETTEXT, sent|defwinproc },
341     { WM_ACTIVATE, sent|parent|wparam, 0 },
342     { WM_WINDOWPOSCHANGING, sent },
343     { WM_WINDOWPOSCHANGING, sent|parent },
344     { WM_NCACTIVATE, sent|wparam, 1 },
345     { WM_ACTIVATE, sent|wparam, 1 },
346     { WM_WINDOWPOSCHANGED, sent },
347     { WM_SIZE, sent|defwinproc },
348     /* (setting focus) */
349     { WM_SHOWWINDOW, sent|wparam, 1 },
350     { WM_WINDOWPOSCHANGING, sent },
351     { WM_NCPAINT, sent },
352     { WM_GETTEXT, sent|defwinproc },
353     { WM_ERASEBKGND, sent },
354     { WM_CTLCOLORDLG, sent|defwinproc },
355     { WM_WINDOWPOSCHANGED, sent },
356     { WM_PAINT, sent },
357     /* (bunch of WM_CTLCOLOR* for each control) */
358     { WM_PAINT, sent|parent },
359     { WM_ENTERIDLE, sent|parent|wparam, 0 },
360     { WM_SETCURSOR, sent|parent },
361     { 0 }
362 };
363 /* SetMenu for NonVisible windows with size change*/
364 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
365     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
366     { WM_NCCALCSIZE, sent|wparam, 1 },
367     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
368     { WM_MOVE, sent|defwinproc },
369     { WM_SIZE, sent|defwinproc },
370     { 0 }
371 };
372 /* SetMenu for NonVisible windows with no size change */
373 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
374     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
375     { WM_NCCALCSIZE, sent|wparam, 1 },
376     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
377     { 0 }
378 };
379 /* SetMenu for Visible windows with size change */
380 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
381     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
382     { WM_NCCALCSIZE, sent|wparam, 1 },
383     { WM_NCPAINT, sent|wparam, 1 },
384     { WM_GETTEXT, sent|defwinproc },
385     { WM_ERASEBKGND, sent|optional },
386     { WM_ACTIVATE, sent|optional },
387     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
388     { WM_MOVE, sent|defwinproc },
389     { WM_SIZE, sent|defwinproc },
390     { 0 }
391 };
392 /* SetMenu for Visible windows with no size change */
393 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
394     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
395     { WM_NCCALCSIZE, sent|wparam, 1 },
396     { WM_NCPAINT, sent|wparam, 1 },
397     { WM_GETTEXT, sent|defwinproc },
398     { WM_ERASEBKGND, sent|optional },
399     { WM_ACTIVATE, sent|optional },
400     { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
401     { 0 }
402 };
403
404 static int sequence_cnt, sequence_size;
405 static struct message* sequence;
406
407 static void add_message(const struct message *msg)
408 {
409     if (!sequence) 
410     {
411         sequence_size = 10;
412         sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
413     }
414     if (sequence_cnt == sequence_size) 
415     {
416         sequence_size *= 2;
417         sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
418     }
419     assert(sequence);
420
421     sequence[sequence_cnt].message = msg->message;
422     sequence[sequence_cnt].flags = msg->flags;
423     sequence[sequence_cnt].wParam = msg->wParam;
424     sequence[sequence_cnt].lParam = msg->lParam;
425
426     sequence_cnt++;
427 }
428
429 static void flush_sequence()
430 {
431     HeapFree(GetProcessHeap(), 0, sequence);
432     sequence = 0;
433     sequence_cnt = sequence_size = 0;
434 }
435
436 static void ok_sequence(const struct message *expected, const char *context)
437 {
438     static const struct message end_of_sequence = { 0, 0, 0, 0 };
439     const struct message *actual;
440     
441     add_message(&end_of_sequence);
442
443     actual = sequence;
444
445     while (expected->message && actual->message)
446     {
447         trace("expected %04x - actual %04x\n", expected->message, actual->message);
448
449         if (expected->message == actual->message)
450         {
451             if (expected->flags & wparam)
452                  ok (expected->wParam == actual->wParam,
453                      "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
454                      context, expected->message, expected->wParam, actual->wParam);
455             if (expected->flags & lparam)
456                  ok (expected->lParam == actual->lParam,
457                      "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
458                      context, expected->message, expected->lParam, actual->lParam);
459             ok ((expected->flags & defwinproc) == (actual->flags & defwinproc),
460                 "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
461                 context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
462             ok ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
463                 "%s: the msg 0x%04x should have been %s\n",
464                 context, expected->message, (expected->flags & posted) ? "posted" : "sent");
465             ok ((expected->flags & parent) == (actual->flags & parent),
466                 "%s: the msg 0x%04x was expected in %s\n",
467                 context, expected->message, (expected->flags & parent) ? "parent" : "child");
468             ok ((expected->flags & hook) == (actual->flags & hook),
469                 "%s: the msg 0x%04x should have been sent by a hook\n",
470                 context, expected->message);
471             expected++;
472             actual++;
473         }
474         else if (expected->flags & optional)
475             expected++;
476         else
477         {
478           todo_wine {
479             ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
480                 context, expected->message, actual->message);
481             expected++;
482             actual++;
483           }
484         }
485     }
486
487   todo_wine {
488     if (expected->message || actual->message)
489         ok (FALSE, "%s: the msg sequence is not complete\n", context);
490   }
491
492     flush_sequence();
493 }
494
495 /* test if we receive the right sequence of messages */
496 static void test_messages(void)
497 {
498     HWND hwnd, hparent, hchild;
499     HWND hchild2, hbutton;
500     HMENU hmenu;
501
502     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
503                            100, 100, 200, 200, 0, 0, 0, NULL);
504     ok (hwnd != 0, "Failed to create overlapped window\n");
505     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
506     
507     ShowWindow(hwnd, SW_SHOW);
508     ok_sequence(WmShowOverlappedSeq, "ShowWindow:overlapped");
509
510     DestroyWindow(hwnd);
511     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped");
512
513     hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
514                               100, 100, 200, 200, 0, 0, 0, NULL);
515     ok (hparent != 0, "Failed to create parent window\n");
516     flush_sequence();
517
518     hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW,
519                              0, 0, 10, 10, hparent, 0, 0, NULL);
520     ok (hchild != 0, "Failed to create child window\n");
521     ok_sequence(WmCreateChildSeq, "CreateWindow:child");
522     
523     hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILDWINDOW,
524                                100, 100, 50, 50, hparent, 0, 0, NULL);
525     ok (hchild2 != 0, "Failed to create child2 window\n");
526     flush_sequence();
527
528     hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILDWINDOW,
529                               0, 100, 50, 50, hchild, 0, 0, NULL);
530     ok (hbutton != 0, "Failed to create button window\n");
531     flush_sequence();
532
533     ShowWindow(hchild, SW_SHOW);
534     ok_sequence(WmShowChildSeq, "ShowWindow:child");
535
536     SetFocus(hchild);
537     flush_sequence();
538
539     MoveWindow(hchild, 10, 10, 20, 20, TRUE);
540     ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child");
541
542     DestroyWindow(hchild);
543     ok_sequence(WmDestroyChildSeq, "DestroyWindow:child");
544     DestroyWindow(hchild2);
545     DestroyWindow(hbutton);
546
547     flush_sequence();
548     hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
549                              0, 0, 100, 100, hparent, 0, 0, NULL);
550     ok (hchild != 0, "Failed to create child popup window\n");
551     ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup");
552     DestroyWindow(hchild);
553
554     /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
555     flush_sequence();
556     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
557                              0, 0, 100, 100, hparent, 0, 0, NULL);
558     ok (hchild != 0, "Failed to create popup window\n");
559     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
560     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
561     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
562     flush_sequence();
563     ShowWindow(hchild, SW_SHOW);
564     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
565     flush_sequence();
566     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
567     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
568     flush_sequence();
569     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
570     ok_sequence(WmShowVisiblePopupSeq_3, "CreateWindow:show_visible_popup_3");
571     DestroyWindow(hchild);
572
573     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
574      * changes nothing in message sequences.
575      */
576     flush_sequence();
577     hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
578                              0, 0, 100, 100, hparent, 0, 0, NULL);
579     ok (hchild != 0, "Failed to create popup window\n");
580     ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup");
581     ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
582     ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
583     flush_sequence();
584     ShowWindow(hchild, SW_SHOW);
585     ok_sequence(WmShowVisiblePopupSeq, "CreateWindow:show_visible_popup");
586     flush_sequence();
587     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
588     ok_sequence(WmShowVisiblePopupSeq_2, "CreateWindow:show_visible_popup_2");
589     DestroyWindow(hchild);
590
591     DestroyWindow(hparent);
592     flush_sequence();
593
594     /* Message sequence for SetMenu */
595     hmenu = CreateMenu();
596     ok (hmenu != 0, "Failed to create menu\n");
597     ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
598     hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
599                            100, 100, 200, 200, 0, hmenu, 0, NULL);
600     ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped");
601     ok (SetMenu(hwnd, 0), "SetMenu");
602     ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange");    
603     ok (SetMenu(hwnd, 0), "SetMenu");
604     ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange");    
605     ShowWindow(hwnd, SW_SHOW);
606     flush_sequence();
607     ok (SetMenu(hwnd, 0), "SetMenu");
608     ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange");    
609     ok (SetMenu(hwnd, hmenu), "SetMenu");
610     ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange");    
611     DestroyWindow(hwnd);
612
613 }
614
615 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
616 {
617     static long defwndproc_counter = 0;
618     LRESULT ret;
619     struct message msg;
620
621     trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
622
623     msg.message = message;
624     msg.flags = sent|wparam|lparam;
625     if (defwndproc_counter) msg.flags |= defwinproc;
626     msg.wParam = wParam;
627     msg.lParam = lParam;
628     add_message(&msg);
629
630     defwndproc_counter++;
631     ret = DefWindowProcA(hwnd, message, wParam, lParam);
632     defwndproc_counter--;
633
634     return ret;
635 }
636
637 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
638 {
639     static long defwndproc_counter = 0;
640     LRESULT ret;
641     struct message msg;
642
643     trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
644
645     msg.message = message;
646     msg.flags = sent|wparam|lparam;
647     if (defwndproc_counter) msg.flags |= defwinproc;
648     msg.wParam = wParam;
649     msg.lParam = lParam;
650     add_message(&msg);
651
652     if (message == WM_CREATE)
653     {
654         DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
655         SetWindowLongA(hwnd, GWL_STYLE, style);
656     }
657
658     defwndproc_counter++;
659     ret = DefWindowProcA(hwnd, message, wParam, lParam);
660     defwndproc_counter--;
661
662     return ret;
663 }
664
665 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
666 {
667     static long defwndproc_counter = 0;
668     LRESULT ret;
669     struct message msg;
670
671     trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
672
673     if (message == WM_PARENTNOTIFY)
674     {
675         msg.message = message;
676         msg.flags = sent|parent|wparam|lparam;
677         if (defwndproc_counter) msg.flags |= defwinproc;
678         msg.wParam = wParam;
679         msg.lParam = lParam;
680         add_message(&msg);
681     }
682
683     defwndproc_counter++;
684     ret = DefWindowProcA(hwnd, message, wParam, lParam);
685     defwndproc_counter--;
686
687     return ret;
688 }
689
690 static BOOL RegisterWindowClasses(void)
691 {
692     WNDCLASSA cls;
693
694     cls.style = 0;
695     cls.lpfnWndProc = MsgCheckProcA;
696     cls.cbClsExtra = 0;
697     cls.cbWndExtra = 0;
698     cls.hInstance = GetModuleHandleA(0);
699     cls.hIcon = 0;
700     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
701     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
702     cls.lpszMenuName = NULL;
703     cls.lpszClassName = "TestWindowClass";
704     if(!RegisterClassA(&cls)) return FALSE;
705
706     cls.lpfnWndProc = PopupMsgCheckProcA;
707     cls.lpszClassName = "TestPopupClass";
708     if(!RegisterClassA(&cls)) return FALSE;
709
710     cls.lpfnWndProc = ParentMsgCheckProcA;
711     cls.lpszClassName = "TestParentClass";
712     if(!RegisterClassA(&cls)) return FALSE;
713
714     cls.lpfnWndProc = DefWindowProcA;
715     cls.lpszClassName = "SimpleWindowClass";
716     if(!RegisterClassA(&cls)) return FALSE;
717
718     return TRUE;
719 }
720
721 static HHOOK hCBT_hook;
722
723 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
724
725     char buf[256];
726
727     trace("CBT: %d, %08x, %08lx\n", nCode, wParam, lParam);
728
729     if (GetClassNameA((HWND)wParam, buf, sizeof(buf)))
730     {
731         if (!strcmp(buf, "TestWindowClass") ||
732             !strcmp(buf, "TestParentClass") ||
733             !strcmp(buf, "TestPopupClass") ||
734             !strcmp(buf, "SimpleWindowClass"))
735         {
736             struct message msg;
737
738             msg.message = nCode;
739             msg.flags = hook;
740             msg.wParam = wParam;
741             msg.lParam = lParam;
742             add_message(&msg);
743         }
744     }
745     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
746 }
747
748 START_TEST(msg)
749 {
750     if (!RegisterWindowClasses()) assert(0);
751
752     hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
753     assert(hCBT_hook);
754
755     test_messages();
756
757     UnhookWindowsHookEx(hCBT_hook);
758 }