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