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