Some more tests for focus behavior when hiding/showing windows.
[wine] / dlls / user / tests / win.c
1 /*
2  * Unit tests for window handling
3  *
4  * Copyright 2002 Bill Medland
5  * Copyright 2002 Alexandre Julliard
6  * Copyright 2003 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 /* To get ICON_SMALL2 with the MSVC headers */
24 #define _WIN32_WINNT 0x0501
25
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35
36 #include "wine/test.h"
37
38 #ifndef SPI_GETDESKWALLPAPER
39 #define SPI_GETDESKWALLPAPER 0x0073
40 #endif
41
42 #define LONG_PTR INT_PTR
43 #define ULONG_PTR UINT_PTR
44
45 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
46
47 static HWND hwndMain, hwndMain2;
48 static HHOOK hhook;
49
50 /* check the values returned by the various parent/owner functions on a given window */
51 static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent,
52                            HWND gw_owner, HWND ga_root, HWND ga_root_owner )
53 {
54     HWND res;
55
56     if (pGetAncestor)
57     {
58         res = pGetAncestor( hwnd, GA_PARENT );
59         ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p\n", res, ga_parent );
60     }
61     res = (HWND)GetWindowLongA( hwnd, GWL_HWNDPARENT );
62     ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %p expected %p\n", res, gwl_parent );
63     res = GetParent( hwnd );
64     ok( res == get_parent, "Wrong result for GetParent %p expected %p\n", res, get_parent );
65     res = GetWindow( hwnd, GW_OWNER );
66     ok( res == gw_owner, "Wrong result for GW_OWNER %p expected %p\n", res, gw_owner );
67     if (pGetAncestor)
68     {
69         res = pGetAncestor( hwnd, GA_ROOT );
70         ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p\n", res, ga_root );
71         res = pGetAncestor( hwnd, GA_ROOTOWNER );
72         ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p\n", res, ga_root_owner );
73     }
74 }
75
76
77 static HWND create_tool_window( LONG style, HWND parent )
78 {
79     HWND ret = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", style,
80                                0, 0, 100, 100, parent, 0, 0, NULL );
81     ok( ret != 0, "Creation failed\n" );
82     return ret;
83 }
84
85 /* test parent and owner values for various combinations */
86 static void test_parent_owner(void)
87 {
88     LONG style;
89     HWND test, owner, ret;
90     HWND desktop = GetDesktopWindow();
91     HWND child = create_tool_window( WS_CHILD, hwndMain );
92
93     trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child );
94
95     /* child without parent, should fail */
96     test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1",
97                            WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL );
98     ok( !test, "WS_CHILD without parent created\n" );
99
100     /* desktop window */
101     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
102     style = GetWindowLongA( desktop, GWL_STYLE );
103     ok( !SetWindowLongA( desktop, GWL_STYLE, WS_POPUP ), "Set GWL_STYLE on desktop succeeded\n" );
104     ok( !SetWindowLongA( desktop, GWL_STYLE, 0 ), "Set GWL_STYLE on desktop succeeded\n" );
105     ok( GetWindowLongA( desktop, GWL_STYLE ) == style, "Desktop style changed\n" );
106
107     /* normal child window */
108     test = create_tool_window( WS_CHILD, hwndMain );
109     trace( "created child %p\n", test );
110     check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain );
111     SetWindowLongA( test, GWL_STYLE, 0 );
112     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
113     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
114     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
115     SetWindowLongA( test, GWL_STYLE, WS_POPUP|WS_CHILD );
116     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
117     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
118     DestroyWindow( test );
119
120     /* normal child window with WS_MAXIMIZE */
121     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, hwndMain );
122     DestroyWindow( test );
123
124     /* normal child window with WS_THICKFRAME */
125     test = create_tool_window( WS_CHILD | WS_THICKFRAME, hwndMain );
126     DestroyWindow( test );
127
128     /* popup window with WS_THICKFRAME */
129     test = create_tool_window( WS_POPUP | WS_THICKFRAME, hwndMain );
130     DestroyWindow( test );
131
132     /* child of desktop */
133     test = create_tool_window( WS_CHILD, desktop );
134     trace( "created child of desktop %p\n", test );
135     check_parents( test, desktop, 0, desktop, 0, test, desktop );
136     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
137     check_parents( test, desktop, 0, 0, 0, test, test );
138     SetWindowLongA( test, GWL_STYLE, 0 );
139     check_parents( test, desktop, 0, 0, 0, test, test );
140     DestroyWindow( test );
141
142     /* child of desktop with WS_MAXIMIZE */
143     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, desktop );
144     DestroyWindow( test );
145
146     /* child of desktop with WS_MINIMIZE */
147     test = create_tool_window( WS_CHILD | WS_MINIMIZE, desktop );
148     DestroyWindow( test );
149
150     /* child of child */
151     test = create_tool_window( WS_CHILD, child );
152     trace( "created child of child %p\n", test );
153     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
154     SetWindowLongA( test, GWL_STYLE, 0 );
155     check_parents( test, child, child, 0, 0, hwndMain, test );
156     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
157     check_parents( test, child, child, 0, 0, hwndMain, test );
158     DestroyWindow( test );
159
160     /* child of child with WS_MAXIMIZE */
161     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, child );
162     DestroyWindow( test );
163
164     /* child of child with WS_MINIMIZE */
165     test = create_tool_window( WS_CHILD | WS_MINIMIZE, child );
166     DestroyWindow( test );
167
168     /* not owned top-level window */
169     test = create_tool_window( 0, 0 );
170     trace( "created top-level %p\n", test );
171     check_parents( test, desktop, 0, 0, 0, test, test );
172     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
173     check_parents( test, desktop, 0, 0, 0, test, test );
174     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
175     check_parents( test, desktop, 0, desktop, 0, test, desktop );
176     DestroyWindow( test );
177
178     /* not owned top-level window with WS_MAXIMIZE */
179     test = create_tool_window( WS_MAXIMIZE, 0 );
180     DestroyWindow( test );
181
182     /* owned top-level window */
183     test = create_tool_window( 0, hwndMain );
184     trace( "created owned top-level %p\n", test );
185     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
186     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
187     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
188     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
189     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
190     DestroyWindow( test );
191
192     /* owned top-level window with WS_MAXIMIZE */
193     test = create_tool_window( WS_MAXIMIZE, hwndMain );
194     DestroyWindow( test );
195
196     /* not owned popup */
197     test = create_tool_window( WS_POPUP, 0 );
198     trace( "created popup %p\n", test );
199     check_parents( test, desktop, 0, 0, 0, test, test );
200     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
201     check_parents( test, desktop, 0, desktop, 0, test, desktop );
202     SetWindowLongA( test, GWL_STYLE, 0 );
203     check_parents( test, desktop, 0, 0, 0, test, test );
204     DestroyWindow( test );
205
206     /* not owned popup with WS_MAXIMIZE */
207     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, 0 );
208     DestroyWindow( test );
209
210     /* owned popup */
211     test = create_tool_window( WS_POPUP, hwndMain );
212     trace( "created owned popup %p\n", test );
213     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
214     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
215     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
216     SetWindowLongA( test, GWL_STYLE, 0 );
217     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
218     DestroyWindow( test );
219
220     /* owned popup with WS_MAXIMIZE */
221     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, hwndMain );
222     DestroyWindow( test );
223
224     /* top-level window owned by child (same as owned by top-level) */
225     test = create_tool_window( 0, child );
226     trace( "created top-level owned by child %p\n", test );
227     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
228     DestroyWindow( test );
229
230     /* top-level window owned by child (same as owned by top-level) with WS_MAXIMIZE */
231     test = create_tool_window( WS_MAXIMIZE, child );
232     DestroyWindow( test );
233
234     /* popup owned by desktop (same as not owned) */
235     test = create_tool_window( WS_POPUP, desktop );
236     trace( "created popup owned by desktop %p\n", test );
237     check_parents( test, desktop, 0, 0, 0, test, test );
238     DestroyWindow( test );
239
240     /* popup owned by desktop (same as not owned) with WS_MAXIMIZE */
241     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, desktop );
242     DestroyWindow( test );
243
244     /* popup owned by child (same as owned by top-level) */
245     test = create_tool_window( WS_POPUP, child );
246     trace( "created popup owned by child %p\n", test );
247     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
248     DestroyWindow( test );
249
250     /* popup owned by child (same as owned by top-level) with WS_MAXIMIZE */
251     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, child );
252     DestroyWindow( test );
253
254     /* not owned popup with WS_CHILD (same as WS_POPUP only) */
255     test = create_tool_window( WS_POPUP | WS_CHILD, 0 );
256     trace( "created WS_CHILD popup %p\n", test );
257     check_parents( test, desktop, 0, 0, 0, test, test );
258     DestroyWindow( test );
259
260     /* not owned popup with WS_CHILD | WS_MAXIMIZE (same as WS_POPUP only) */
261     test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, 0 );
262     DestroyWindow( test );
263
264     /* owned popup with WS_CHILD (same as WS_POPUP only) */
265     test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain );
266     trace( "created owned WS_CHILD popup %p\n", test );
267     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
268     DestroyWindow( test );
269
270     /* owned popup with WS_CHILD (same as WS_POPUP only) with WS_MAXIMIZE */
271     test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, hwndMain );
272     DestroyWindow( test );
273
274     /******************** parent changes *************************/
275     trace( "testing parent changes\n" );
276
277     /* desktop window */
278     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
279 #if 0 /* this test succeeds on NT but crashes on win9x systems */
280     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
281     ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop\n" );
282     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
283     ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop\n" );
284     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
285 #endif
286     /* normal child window */
287     test = create_tool_window( WS_CHILD, hwndMain );
288     trace( "created child %p\n", test );
289
290     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
291     ok( ret == hwndMain, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain );
292     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
293
294     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
295     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain2 );
296     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
297
298     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)desktop );
299     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
300     check_parents( test, desktop, 0, desktop, 0, test, desktop );
301
302     /* window is now child of desktop so GWL_HWNDPARENT changes owner from now on */
303     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
304     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
305     check_parents( test, desktop, child, desktop, child, test, desktop );
306
307     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
308     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
309     check_parents( test, desktop, 0, desktop, 0, test, desktop );
310     DestroyWindow( test );
311
312     /* not owned top-level window */
313     test = create_tool_window( 0, 0 );
314     trace( "created top-level %p\n", test );
315
316     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
317     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
318     check_parents( test, desktop, hwndMain2, 0, hwndMain2, test, test );
319
320     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
321     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain2 );
322     check_parents( test, desktop, child, 0, child, test, test );
323
324     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
325     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
326     check_parents( test, desktop, 0, 0, 0, test, test );
327     DestroyWindow( test );
328
329     /* not owned popup */
330     test = create_tool_window( WS_POPUP, 0 );
331     trace( "created popup %p\n", test );
332
333     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
334     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
335     check_parents( test, desktop, hwndMain2, hwndMain2, hwndMain2, test, hwndMain2 );
336
337     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
338     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain2 );
339     check_parents( test, desktop, child, child, child, test, hwndMain );
340
341     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
342     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
343     check_parents( test, desktop, 0, 0, 0, test, test );
344     DestroyWindow( test );
345
346     /* normal child window */
347     test = create_tool_window( WS_CHILD, hwndMain );
348     trace( "created child %p\n", test );
349
350     ret = SetParent( test, desktop );
351     ok( ret == hwndMain, "SetParent return value %p expected %p\n", ret, hwndMain );
352     check_parents( test, desktop, 0, desktop, 0, test, desktop );
353
354     ret = SetParent( test, child );
355     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
356     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
357
358     ret = SetParent( test, hwndMain2 );
359     ok( ret == child, "SetParent return value %p expected %p\n", ret, child );
360     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
361     DestroyWindow( test );
362
363     /* not owned top-level window */
364     test = create_tool_window( 0, 0 );
365     trace( "created top-level %p\n", test );
366
367     ret = SetParent( test, child );
368     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
369     check_parents( test, child, child, 0, 0, hwndMain, test );
370     DestroyWindow( test );
371
372     /* owned popup */
373     test = create_tool_window( WS_POPUP, hwndMain2 );
374     trace( "created owned popup %p\n", test );
375
376     ret = SetParent( test, child );
377     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
378     check_parents( test, child, child, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
379
380     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)hwndMain );
381     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
382     check_parents( test, hwndMain, hwndMain, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
383     DestroyWindow( test );
384
385     /**************** test owner destruction *******************/
386
387     /* owned child popup */
388     owner = create_tool_window( 0, 0 );
389     test = create_tool_window( WS_POPUP, owner );
390     trace( "created owner %p and popup %p\n", owner, test );
391     ret = SetParent( test, child );
392     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
393     check_parents( test, child, child, owner, owner, hwndMain, owner );
394     /* window is now child of 'child' but owned by 'owner' */
395     DestroyWindow( owner );
396     ok( IsWindow(test), "Window %p destroyed by owner destruction\n", test );
397     check_parents( test, child, child, owner, owner, hwndMain, owner );
398     ok( !IsWindow(owner), "Owner %p not destroyed\n", owner );
399     DestroyWindow(test);
400
401     /* owned top-level popup */
402     owner = create_tool_window( 0, 0 );
403     test = create_tool_window( WS_POPUP, owner );
404     trace( "created owner %p and popup %p\n", owner, test );
405     check_parents( test, desktop, owner, owner, owner, test, owner );
406     DestroyWindow( owner );
407     ok( !IsWindow(test), "Window %p not destroyed by owner destruction\n", test );
408
409     /* top-level popup owned by child */
410     owner = create_tool_window( WS_CHILD, hwndMain2 );
411     test = create_tool_window( WS_POPUP, 0 );
412     trace( "created owner %p and popup %p\n", owner, test );
413     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)owner );
414     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
415     check_parents( test, desktop, owner, owner, owner, test, hwndMain2 );
416     DestroyWindow( owner );
417     ok( IsWindow(test), "Window %p destroyed by owner destruction\n", test );
418     ok( !IsWindow(owner), "Owner %p not destroyed\n", owner );
419     check_parents( test, desktop, owner, owner, owner, test, owner );
420     DestroyWindow(test);
421
422     /* final cleanup */
423     DestroyWindow(child);
424 }
425
426
427 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
428 {
429     switch (msg)
430     {
431         case WM_GETMINMAXINFO:
432         {
433             MINMAXINFO* minmax = (MINMAXINFO *)lparam;
434
435             trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam);
436             trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n"
437                   "       ptMinTrackSize (%ld,%ld), ptMaxTrackSize (%ld,%ld)\n",
438                   minmax->ptReserved.x, minmax->ptReserved.y,
439                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
440                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
441                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
442                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
443             SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021);
444             break;
445         }
446         case WM_WINDOWPOSCHANGING:
447         {
448             BOOL is_win9x = GetWindowLongW(hwnd, GWL_WNDPROC) == 0;
449             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
450             trace("main: WM_WINDOWPOSCHANGING\n");
451             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
452                    winpos->hwnd, winpos->hwndInsertAfter,
453                    winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
454             if (!(winpos->flags & SWP_NOMOVE))
455             {
456                 ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x);
457                 ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y);
458             }
459             /* Win9x does not fixup cx/xy for WM_WINDOWPOSCHANGING */
460             if (!(winpos->flags & SWP_NOSIZE) && !is_win9x)
461             {
462                 ok(winpos->cx >= 0 && winpos->cx <= 32767, "bad winpos->cx %d\n", winpos->cx);
463                 ok(winpos->cy >= 0 && winpos->cy <= 32767, "bad winpos->cy %d\n", winpos->cy);
464             }
465             break;
466         }
467         case WM_WINDOWPOSCHANGED:
468         {
469             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
470             trace("main: WM_WINDOWPOSCHANGED\n");
471             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
472                    winpos->hwnd, winpos->hwndInsertAfter,
473                    winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
474             ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x);
475             ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y);
476
477             ok(winpos->cx >= 0 && winpos->cx <= 32767, "bad winpos->cx %d\n", winpos->cx);
478             ok(winpos->cy >= 0 && winpos->cy <= 32767, "bad winpos->cy %d\n", winpos->cy);
479             break;
480         }
481         case WM_NCCREATE:
482         {
483             BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021;
484             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
485
486             trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style);
487             if (got_getminmaxinfo)
488                 trace("%p got WM_GETMINMAXINFO\n", hwnd);
489
490             if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
491                 ok(got_getminmaxinfo, "main: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
492             else
493                 ok(!got_getminmaxinfo, "main: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
494             break;
495         }
496     }
497
498     return DefWindowProcA(hwnd, msg, wparam, lparam);
499 }
500
501 static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
502 {
503     switch (msg)
504     {
505         case WM_GETMINMAXINFO:
506         {
507             MINMAXINFO* minmax = (MINMAXINFO *)lparam;
508
509             trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam);
510             trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n"
511                   "       ptMinTrackSize (%ld,%ld), ptMaxTrackSize (%ld,%ld)\n",
512                   minmax->ptReserved.x, minmax->ptReserved.y,
513                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
514                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
515                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
516                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
517             SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021);
518             break;
519         }
520         case WM_NCCREATE:
521         {
522             BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021;
523             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
524
525             trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style);
526             if (got_getminmaxinfo)
527                 trace("%p got WM_GETMINMAXINFO\n", hwnd);
528
529             if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
530                 ok(got_getminmaxinfo, "tool: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
531             else
532                 ok(!got_getminmaxinfo, "tool: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
533             break;
534         }
535     }
536
537     return DefWindowProcA(hwnd, msg, wparam, lparam);
538 }
539
540 static BOOL RegisterWindowClasses(void)
541 {
542     WNDCLASSA cls;
543
544     cls.style = 0;
545     cls.lpfnWndProc = main_window_procA;
546     cls.cbClsExtra = 0;
547     cls.cbWndExtra = 0;
548     cls.hInstance = GetModuleHandleA(0);
549     cls.hIcon = 0;
550     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
551     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
552     cls.lpszMenuName = NULL;
553     cls.lpszClassName = "MainWindowClass";
554
555     if(!RegisterClassA(&cls)) return FALSE;
556
557     cls.style = 0;
558     cls.lpfnWndProc = tool_window_procA;
559     cls.cbClsExtra = 0;
560     cls.cbWndExtra = 0;
561     cls.hInstance = GetModuleHandleA(0);
562     cls.hIcon = 0;
563     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
564     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
565     cls.lpszMenuName = NULL;
566     cls.lpszClassName = "ToolWindowClass";
567
568     if(!RegisterClassA(&cls)) return FALSE;
569
570     return TRUE;
571 }
572
573 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
574
575     static const char *CBT_code_name[10] = {
576         "HCBT_MOVESIZE",
577         "HCBT_MINMAX",
578         "HCBT_QS",
579         "HCBT_CREATEWND",
580         "HCBT_DESTROYWND",
581         "HCBT_ACTIVATE",
582         "HCBT_CLICKSKIPPED",
583         "HCBT_KEYSKIPPED",
584         "HCBT_SYSCOMMAND",
585         "HCBT_SETFOCUS" };
586     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
587
588     trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam);
589
590     switch (nCode)
591     {
592         case HCBT_CREATEWND:
593         {
594             LONG style;
595             CBT_CREATEWNDA *createwnd = (CBT_CREATEWNDA *)lParam;
596             trace("HCBT_CREATEWND: hwnd %p, parent %p, style %08lx\n",
597                   (HWND)wParam, createwnd->lpcs->hwndParent, createwnd->lpcs->style);
598             ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n");
599
600             /* WS_VISIBLE should be turned off yet */
601             style = createwnd->lpcs->style & ~WS_VISIBLE;
602             ok(style == GetWindowLongA((HWND)wParam, GWL_STYLE),
603                 "style of hwnd and style in the CREATESTRUCT do not match: %08lx != %08lx\n",
604                 GetWindowLongA((HWND)wParam, GWL_STYLE), style);
605             break;
606         }
607     }
608
609     return CallNextHookEx(hhook, nCode, wParam, lParam);
610 }
611
612 static void test_shell_window()
613 {
614     BOOL ret;
615     DWORD error;
616     HMODULE hinst, hUser32;
617     BOOL (WINAPI*SetShellWindow)(HWND);
618     BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
619     HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5;
620     HWND shellWindow, nextWnd;
621
622     shellWindow = GetShellWindow();
623     hinst = GetModuleHandle(0);
624     hUser32 = GetModuleHandleA("user32");
625
626     SetShellWindow = (void *)GetProcAddress(hUser32, "SetShellWindow");
627     SetShellWindowEx = (void *)GetProcAddress(hUser32, "SetShellWindowEx");
628
629     trace("previous shell window: %p\n", shellWindow);
630
631     if (shellWindow) {
632         DWORD pid;
633         HANDLE hProcess;
634
635         ret = DestroyWindow(shellWindow);
636         error = GetLastError();
637
638         ok(!ret, "DestroyWindow(shellWindow)\n");
639         /* passes on Win XP, but not on Win98
640         ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n"); */
641
642         /* close old shell instance */
643         GetWindowThreadProcessId(shellWindow, &pid);
644         hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
645         ret = TerminateProcess(hProcess, 0);
646         ok(ret, "termination of previous shell process failed: GetLastError()=%ld\n", GetLastError());
647         WaitForSingleObject(hProcess, INFINITE);    /* wait for termination */
648         CloseHandle(hProcess);
649     }
650
651     hwnd1 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0);
652     trace("created window 1: %p\n", hwnd1);
653
654     ret = SetShellWindow(hwnd1);
655     ok(ret, "first call to SetShellWindow(hwnd1)\n");
656     shellWindow = GetShellWindow();
657     ok(shellWindow==hwnd1, "wrong shell window: %p\n", shellWindow);
658
659     ret = SetShellWindow(hwnd1);
660     ok(!ret, "second call to SetShellWindow(hwnd1)\n");
661
662     ret = SetShellWindow(0);
663     error = GetLastError();
664     /* passes on Win XP, but not on Win98
665     ok(!ret, "reset shell window by SetShellWindow(0)\n");
666     ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */
667
668     ret = SetShellWindow(hwnd1);
669     /* passes on Win XP, but not on Win98
670     ok(!ret, "third call to SetShellWindow(hwnd1)\n"); */
671
672     todo_wine
673     {
674         SetWindowLong(hwnd1, GWL_EXSTYLE, GetWindowLong(hwnd1,GWL_EXSTYLE)|WS_EX_TOPMOST);
675         ret = GetWindowLong(hwnd1,GWL_EXSTYLE)&WS_EX_TOPMOST? TRUE: FALSE;
676         ok(!ret, "SetWindowExStyle(hwnd1, WS_EX_TOPMOST)\n");
677     }
678
679     ret = DestroyWindow(hwnd1);
680     ok(ret, "DestroyWindow(hwnd1)\n");
681
682     hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0);
683     trace("created window 2: %p\n", hwnd2);
684     ret = SetShellWindow(hwnd2);
685     ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST\n");
686
687     hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0);
688     trace("created window 3: %p\n", hwnd3);
689
690     hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0);
691     trace("created window 4: %p\n", hwnd4);
692
693     nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
694     ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd);
695
696     ret = SetShellWindow(hwnd4);
697     ok(ret, "SetShellWindow(hwnd4)\n");
698     shellWindow = GetShellWindow();
699     ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow);
700
701     nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
702     ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd);
703
704     ret = SetWindowPos(hwnd4, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
705     ok(ret, "SetWindowPos(hwnd4, HWND_TOPMOST)\n");
706
707     ret = SetWindowPos(hwnd4, hwnd3, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
708     ok(ret, "SetWindowPos(hwnd4, hwnd3\n");
709
710     ret = SetShellWindow(hwnd3);
711     ok(!ret, "SetShellWindow(hwnd3)\n");
712     shellWindow = GetShellWindow();
713     ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow);
714
715     hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0);
716     trace("created window 5: %p\n", hwnd5);
717     ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
718     ok(ret, "SetWindowPos(hwnd4, hwnd5)\n");
719
720     todo_wine
721     {
722         nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
723         ok(nextWnd==0, "wrong next window for hwnd4 after SetWindowPos(): %p - expected 0\n", nextWnd);
724     }
725
726     /* destroy test windows */
727     DestroyWindow(hwnd2);
728     DestroyWindow(hwnd3);
729     DestroyWindow(hwnd4);
730     DestroyWindow(hwnd5);
731 }
732
733 /************** MDI test ****************/
734
735 static const char mdi_lParam_test_message[] = "just a test string";
736
737 static void test_MDI_create(HWND parent, HWND mdi_client)
738 {
739     MDICREATESTRUCTA mdi_cs;
740     HWND mdi_child;
741     static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0};
742     static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0};
743     BOOL isWin9x = FALSE;
744
745     mdi_cs.szClass = "MDI_child_Class_1";
746     mdi_cs.szTitle = "MDI child";
747     mdi_cs.hOwner = GetModuleHandle(0);
748     mdi_cs.x = CW_USEDEFAULT;
749     mdi_cs.y = CW_USEDEFAULT;
750     mdi_cs.cx = CW_USEDEFAULT;
751     mdi_cs.cy = CW_USEDEFAULT;
752     mdi_cs.style = 0;
753     mdi_cs.lParam = (LPARAM)mdi_lParam_test_message;
754     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
755     ok(mdi_child != 0, "MDI child creation failed\n");
756     DestroyWindow(mdi_child);
757
758     mdi_cs.style = 0x7fffffff; /* without WS_POPUP */
759     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
760     ok(mdi_child != 0, "MDI child creation failed\n");
761     DestroyWindow(mdi_child);
762
763     mdi_cs.style = 0xffffffff; /* with WS_POPUP */
764     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
765     if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
766     {
767         ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
768         DestroyWindow(mdi_child);
769     }
770     else
771         ok(mdi_child != 0, "MDI child creation failed\n");
772
773     /* test MDICREATESTRUCT A<->W mapping */
774     /* MDICREATESTRUCTA and MDICREATESTRUCTW have the same layout */
775     mdi_cs.style = 0;
776     mdi_cs.szClass = (LPCSTR)classW;
777     mdi_cs.szTitle = (LPCSTR)titleW;
778     SetLastError(0xdeadbeef);
779     mdi_child = (HWND)SendMessageW(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
780     if (!mdi_child)
781     {
782         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
783             isWin9x = TRUE;
784         else
785             ok(mdi_child != 0, "MDI child creation failed\n");
786     }
787     DestroyWindow(mdi_child);
788
789     mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
790                                  0,
791                                  CW_USEDEFAULT, CW_USEDEFAULT,
792                                  CW_USEDEFAULT, CW_USEDEFAULT,
793                                  mdi_client, GetModuleHandle(0),
794                                  (LPARAM)mdi_lParam_test_message);
795     ok(mdi_child != 0, "MDI child creation failed\n");
796     DestroyWindow(mdi_child);
797
798     mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
799                                  0x7fffffff, /* without WS_POPUP */
800                                  CW_USEDEFAULT, CW_USEDEFAULT,
801                                  CW_USEDEFAULT, CW_USEDEFAULT,
802                                  mdi_client, GetModuleHandle(0),
803                                  (LPARAM)mdi_lParam_test_message);
804     ok(mdi_child != 0, "MDI child creation failed\n");
805     DestroyWindow(mdi_child);
806
807     mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
808                                  0xffffffff, /* with WS_POPUP */
809                                  CW_USEDEFAULT, CW_USEDEFAULT,
810                                  CW_USEDEFAULT, CW_USEDEFAULT,
811                                  mdi_client, GetModuleHandle(0),
812                                  (LPARAM)mdi_lParam_test_message);
813     if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
814     {
815         ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
816         DestroyWindow(mdi_child);
817     }
818     else
819         ok(mdi_child != 0, "MDI child creation failed\n");
820
821     /* test MDICREATESTRUCT A<->W mapping */
822     SetLastError(0xdeadbeef);
823     mdi_child = CreateMDIWindowW(classW, titleW,
824                                  0,
825                                  CW_USEDEFAULT, CW_USEDEFAULT,
826                                  CW_USEDEFAULT, CW_USEDEFAULT,
827                                  mdi_client, GetModuleHandle(0),
828                                  (LPARAM)mdi_lParam_test_message);
829     if (!mdi_child)
830     {
831         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
832             isWin9x = TRUE;
833         else
834             ok(mdi_child != 0, "MDI child creation failed\n");
835     }
836     DestroyWindow(mdi_child);
837
838     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
839                                 0,
840                                 CW_USEDEFAULT, CW_USEDEFAULT,
841                                 CW_USEDEFAULT, CW_USEDEFAULT,
842                                 mdi_client, 0, GetModuleHandle(0),
843                                 (LPVOID)mdi_lParam_test_message);
844     ok(mdi_child != 0, "MDI child creation failed\n");
845     DestroyWindow(mdi_child);
846
847     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
848                                 0x7fffffff, /* without WS_POPUP */
849                                 CW_USEDEFAULT, CW_USEDEFAULT,
850                                 CW_USEDEFAULT, CW_USEDEFAULT,
851                                 mdi_client, 0, GetModuleHandle(0),
852                                 (LPVOID)mdi_lParam_test_message);
853     ok(mdi_child != 0, "MDI child creation failed\n");
854     DestroyWindow(mdi_child);
855
856     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
857                                 0xffffffff, /* with WS_POPUP */
858                                 CW_USEDEFAULT, CW_USEDEFAULT,
859                                 CW_USEDEFAULT, CW_USEDEFAULT,
860                                 mdi_client, 0, GetModuleHandle(0),
861                                 (LPVOID)mdi_lParam_test_message);
862     if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
863     {
864         ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
865         DestroyWindow(mdi_child);
866     }
867     else
868         ok(mdi_child != 0, "MDI child creation failed\n");
869
870     /* test MDICREATESTRUCT A<->W mapping */
871     SetLastError(0xdeadbeef);
872     mdi_child = CreateWindowExW(WS_EX_MDICHILD, classW, titleW,
873                                 0,
874                                 CW_USEDEFAULT, CW_USEDEFAULT,
875                                 CW_USEDEFAULT, CW_USEDEFAULT,
876                                 mdi_client, 0, GetModuleHandle(0),
877                                 (LPVOID)mdi_lParam_test_message);
878     if (!mdi_child)
879     {
880         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
881             isWin9x = TRUE;
882         else
883             ok(mdi_child != 0, "MDI child creation failed\n");
884     }
885     DestroyWindow(mdi_child);
886
887     /* This test fails on Win9x */
888     if (!isWin9x)
889     {
890         mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child",
891                                 WS_CHILD,
892                                 CW_USEDEFAULT, CW_USEDEFAULT,
893                                 CW_USEDEFAULT, CW_USEDEFAULT,
894                                 parent, 0, GetModuleHandle(0),
895                                 (LPVOID)mdi_lParam_test_message);
896         ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n");
897     }
898
899     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
900                                 WS_CHILD, /* without WS_POPUP */
901                                 CW_USEDEFAULT, CW_USEDEFAULT,
902                                 CW_USEDEFAULT, CW_USEDEFAULT,
903                                 mdi_client, 0, GetModuleHandle(0),
904                                 (LPVOID)mdi_lParam_test_message);
905     ok(mdi_child != 0, "MDI child creation failed\n");
906     DestroyWindow(mdi_child);
907
908     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
909                                 WS_CHILD | WS_POPUP, /* with WS_POPUP */
910                                 CW_USEDEFAULT, CW_USEDEFAULT,
911                                 CW_USEDEFAULT, CW_USEDEFAULT,
912                                 mdi_client, 0, GetModuleHandle(0),
913                                 (LPVOID)mdi_lParam_test_message);
914     ok(mdi_child != 0, "MDI child creation failed\n");
915     DestroyWindow(mdi_child);
916 }
917
918 static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
919 {
920     switch (msg)
921     {
922         case WM_NCCREATE:
923         case WM_CREATE:
924         {
925             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
926             MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams;
927
928             ok(cs->dwExStyle & WS_EX_MDICHILD, "WS_EX_MDICHILD should be set\n");
929             ok(mdi_cs->lParam == (LPARAM)mdi_lParam_test_message, "wrong mdi_cs->lParam\n");
930
931             ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_1"), "wrong class name\n");
932             ok(!lstrcmpA(cs->lpszClass, mdi_cs->szClass), "class name does not match\n");
933             ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
934             ok(!lstrcmpA(cs->lpszName, mdi_cs->szTitle), "title does not match\n");
935             ok(cs->hInstance == mdi_cs->hOwner, "%p != %p\n", cs->hInstance, mdi_cs->hOwner);
936
937             /* MDICREATESTRUCT should have original values */
938             ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff,
939                 "mdi_cs->style does not match (%08lx)\n", mdi_cs->style);
940             ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x);
941             ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y);
942             ok(mdi_cs->cx == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cx);
943             ok(mdi_cs->cy == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cy);
944
945             /* CREATESTRUCT should have fixed values */
946             ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);
947             ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
948
949             /* cx/cy == CW_USEDEFAULT are translated to NOT zero values */
950             ok(cs->cx != CW_USEDEFAULT && cs->cx != 0, "%d == CW_USEDEFAULT\n", cs->cx);
951             ok(cs->cy != CW_USEDEFAULT && cs->cy != 0, "%d == CW_USEDEFAULT\n", cs->cy);
952
953             ok(!(cs->style & WS_POPUP), "WS_POPUP is not allowed\n");
954
955             if (GetWindowLongA(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
956             {
957                 LONG style = mdi_cs->style | WS_CHILD | WS_CLIPSIBLINGS;
958                 ok(cs->style == style,
959                    "cs->style does not match (%08lx)\n", cs->style);
960             }
961             else
962             {
963                 LONG style = mdi_cs->style;
964                 style &= ~WS_POPUP;
965                 style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
966                     WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
967                 ok(cs->style == style,
968                    "cs->style does not match (%08lx)\n", cs->style);
969             }
970             break;
971         }
972     }
973     return DefMDIChildProcA(hwnd, msg, wparam, lparam);
974 }
975
976 static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
977 {
978     switch (msg)
979     {
980         case WM_NCCREATE:
981         case WM_CREATE:
982         {
983             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
984
985             ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n");
986             ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n");
987
988             ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_2"), "wrong class name\n");
989             ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
990
991             /* CREATESTRUCT should have fixed values */
992             /* For some reason Win9x doesn't translate cs->x from CW_USEDEFAULT,
993                while NT does. */
994             /*ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);*/
995             ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
996
997             /* cx/cy == CW_USEDEFAULT are translated to 0 */
998             ok(cs->cx == 0, "%d != 0\n", cs->cx);
999             ok(cs->cy == 0, "%d != 0\n", cs->cy);
1000             break;
1001         }
1002     }
1003     return DefWindowProcA(hwnd, msg, wparam, lparam);
1004 }
1005
1006 static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1007 {
1008     static HWND mdi_client;
1009
1010     switch (msg)
1011     {
1012         case WM_CREATE:
1013         {
1014             CLIENTCREATESTRUCT client_cs;
1015             RECT rc;
1016
1017             GetClientRect(hwnd, &rc);
1018
1019             client_cs.hWindowMenu = 0;
1020             client_cs.idFirstChild = 1;
1021
1022             /* MDIClient without MDIS_ALLCHILDSTYLES */
1023             mdi_client = CreateWindowExA(0, "mdiclient",
1024                                          NULL,
1025                                          WS_CHILD /*| WS_VISIBLE*/,
1026                                           /* tests depend on a not zero MDIClient size */
1027                                          0, 0, rc.right, rc.bottom,
1028                                          hwnd, 0, GetModuleHandle(0),
1029                                          (LPVOID)&client_cs);
1030             assert(mdi_client);
1031             test_MDI_create(hwnd, mdi_client);
1032             DestroyWindow(mdi_client);
1033
1034             /* MDIClient with MDIS_ALLCHILDSTYLES */
1035             mdi_client = CreateWindowExA(0, "mdiclient",
1036                                          NULL,
1037                                          WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/,
1038                                           /* tests depend on a not zero MDIClient size */
1039                                          0, 0, rc.right, rc.bottom,
1040                                          hwnd, 0, GetModuleHandle(0),
1041                                          (LPVOID)&client_cs);
1042             assert(mdi_client);
1043             test_MDI_create(hwnd, mdi_client);
1044             DestroyWindow(mdi_client);
1045             break;
1046         }
1047
1048         case WM_CLOSE:
1049             PostQuitMessage(0);
1050             break;
1051     }
1052     return DefFrameProcA(hwnd, mdi_client, msg, wparam, lparam);
1053 }
1054
1055 static BOOL mdi_RegisterWindowClasses(void)
1056 {
1057     WNDCLASSA cls;
1058
1059     cls.style = 0;
1060     cls.lpfnWndProc = mdi_main_wnd_procA;
1061     cls.cbClsExtra = 0;
1062     cls.cbWndExtra = 0;
1063     cls.hInstance = GetModuleHandleA(0);
1064     cls.hIcon = 0;
1065     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1066     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1067     cls.lpszMenuName = NULL;
1068     cls.lpszClassName = "MDI_parent_Class";
1069     if(!RegisterClassA(&cls)) return FALSE;
1070
1071     cls.lpfnWndProc = mdi_child_wnd_proc_1;
1072     cls.lpszClassName = "MDI_child_Class_1";
1073     if(!RegisterClassA(&cls)) return FALSE;
1074
1075     cls.lpfnWndProc = mdi_child_wnd_proc_2;
1076     cls.lpszClassName = "MDI_child_Class_2";
1077     if(!RegisterClassA(&cls)) return FALSE;
1078
1079     return TRUE;
1080 }
1081
1082 static void test_mdi(void)
1083 {
1084     HWND mdi_hwndMain;
1085     /*MSG msg;*/
1086
1087     if (!mdi_RegisterWindowClasses()) assert(0);
1088
1089     mdi_hwndMain = CreateWindowExA(0, "MDI_parent_Class", "MDI parent window",
1090                                    WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1091                                    WS_MAXIMIZEBOX /*| WS_VISIBLE*/,
1092                                    100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1093                                    GetDesktopWindow(), 0,
1094                                    GetModuleHandle(0), NULL);
1095     assert(mdi_hwndMain);
1096 /*
1097     while(GetMessage(&msg, 0, 0, 0))
1098     {
1099         TranslateMessage(&msg);
1100         DispatchMessage(&msg);
1101     }
1102 */
1103 }
1104
1105 static void test_icons(void)
1106 {
1107     WNDCLASSEXA cls;
1108     HWND hwnd;
1109     HICON icon = LoadIconA(0, (LPSTR)IDI_APPLICATION);
1110     HICON icon2 = LoadIconA(0, (LPSTR)IDI_QUESTION);
1111     HICON small_icon = LoadImageA(0, (LPSTR)IDI_APPLICATION, IMAGE_ICON,
1112                                   GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED );
1113     HICON res;
1114
1115     cls.cbSize = sizeof(cls);
1116     cls.style = 0;
1117     cls.lpfnWndProc = DefWindowProcA;
1118     cls.cbClsExtra = 0;
1119     cls.cbWndExtra = 0;
1120     cls.hInstance = 0;
1121     cls.hIcon = LoadIconA(0, (LPSTR)IDI_HAND);
1122     cls.hIconSm = small_icon;
1123     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1124     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1125     cls.lpszMenuName = NULL;
1126     cls.lpszClassName = "IconWindowClass";
1127
1128     RegisterClassExA(&cls);
1129
1130     hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0,
1131                            100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL);
1132     assert( hwnd );
1133
1134     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1135     ok( res == 0, "wrong big icon %p/0\n", res );
1136     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon );
1137     ok( res == 0, "wrong previous big icon %p/0\n", res );
1138     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1139     ok( res == icon, "wrong big icon after set %p/%p\n", res, icon );
1140     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 );
1141     ok( res == icon, "wrong previous big icon %p/%p\n", res, icon );
1142     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1143     ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 );
1144
1145     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
1146     ok( res == 0, "wrong small icon %p/0\n", res );
1147     /* this test is XP specific */
1148     /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
1149     ok( res != 0, "wrong small icon %p\n", res );*/
1150     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon );
1151     ok( res == 0, "wrong previous small icon %p/0\n", res );
1152     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
1153     ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );
1154     /* this test is XP specific */
1155     /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
1156     ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );*/
1157     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon );
1158     ok( res == icon, "wrong previous small icon %p/%p\n", res, icon );
1159     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
1160     ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );
1161     /* this test is XP specific */
1162     /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
1163     ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );*/
1164
1165     /* make sure the big icon hasn't changed */
1166     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1167     ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 );
1168 }
1169
1170 static void test_SetWindowPos(HWND hwnd)
1171 {
1172     SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOMOVE);
1173     SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOMOVE);
1174
1175     SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOSIZE);
1176     SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOSIZE);
1177 }
1178
1179 static void test_SetMenu(HWND parent)
1180 {
1181     HWND child;
1182     HMENU hMenu, ret;
1183
1184     hMenu = CreateMenu();
1185     assert(hMenu);
1186
1187     /* parent */
1188     ret = GetMenu(parent);
1189     ok(ret == 0, "unexpected menu id %p\n", ret);
1190
1191     ok(!SetMenu(parent, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
1192     ret = GetMenu(parent);
1193     ok(ret == 0, "unexpected menu id %p\n", ret);
1194
1195     ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
1196     ret = GetMenu(parent);
1197     ok(ret == (HMENU)hMenu, "unexpected menu id %p\n", ret);
1198
1199     ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
1200     ret = GetMenu(parent);
1201     ok(ret == 0, "unexpected menu id %p\n", ret);
1202  
1203     /* child */
1204     child = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, parent, (HMENU)10, 0, NULL);
1205     assert(child);
1206
1207     ret = GetMenu(child);
1208     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1209
1210     ok(!SetMenu(child, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
1211     ret = GetMenu(child);
1212     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1213
1214     ok(!SetMenu(child, hMenu), "SetMenu on a child window should fail\n");
1215     ret = GetMenu(child);
1216     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1217
1218     ok(!SetMenu(child, 0), "SetMenu(0) on a child window should fail\n");
1219     ret = GetMenu(child);
1220     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1221
1222     DestroyWindow(child);
1223     DestroyMenu(hMenu);
1224 }
1225
1226 static void test_window_tree(HWND parent, const DWORD *style, const int *order, int total)
1227 {
1228     HWND child[5], hwnd;
1229     int i;
1230
1231     assert(total <= 5);
1232
1233     hwnd = GetWindow(parent, GW_CHILD);
1234     ok(!hwnd, "have to start without children to perform the test\n");
1235
1236     for (i = 0; i < total; i++)
1237     {
1238         child[i] = CreateWindowExA(0, "static", "", style[i], 0,0,10,10,
1239                                    parent, 0, 0, NULL);
1240         trace("child[%d] = %p\n", i, child[i]);
1241         ok(child[i] != 0, "CreateWindowEx failed to create child window\n");
1242     }
1243
1244     hwnd = GetWindow(parent, GW_CHILD);
1245     ok(hwnd != 0, "GetWindow(GW_CHILD) failed\n");
1246     ok(hwnd == GetWindow(child[total - 1], GW_HWNDFIRST), "GW_HWNDFIRST is wrong\n");
1247     ok(child[order[total - 1]] == GetWindow(child[0], GW_HWNDLAST), "GW_HWNDLAST is wrong\n");
1248
1249     for (i = 0; i < total; i++)
1250     {
1251         trace("hwnd[%d] = %p\n", i, hwnd);
1252         ok(child[order[i]] == hwnd, "Z order of child #%d is wrong\n", i);
1253
1254         hwnd = GetWindow(hwnd, GW_HWNDNEXT);
1255     }
1256
1257     for (i = 0; i < total; i++)
1258         ok(DestroyWindow(child[i]), "DestroyWindow failed\n");
1259 }
1260
1261 static void test_children_zorder(HWND parent)
1262 {
1263     const DWORD simple_style[5] = { WS_CHILD, WS_CHILD, WS_CHILD, WS_CHILD,
1264                                     WS_CHILD };
1265     const int simple_order[5] = { 0, 1, 2, 3, 4 };
1266
1267     const DWORD complex_style[5] = { WS_CHILD, WS_CHILD | WS_MAXIMIZE,
1268                              WS_CHILD | WS_VISIBLE, WS_CHILD,
1269                              WS_CHILD | WS_MAXIMIZE | WS_VISIBLE };
1270     const int complex_order_1[1] = { 0 };
1271     const int complex_order_2[2] = { 1, 0 };
1272     const int complex_order_3[3] = { 1, 0, 2 };
1273     const int complex_order_4[4] = { 1, 0, 2, 3 };
1274     const int complex_order_5[5] = { 4, 1, 0, 2, 3 };
1275
1276     /* simple WS_CHILD */
1277     test_window_tree(parent, simple_style, simple_order, 5);
1278
1279     /* complex children styles */
1280     test_window_tree(parent, complex_style, complex_order_1, 1);
1281     test_window_tree(parent, complex_style, complex_order_2, 2);
1282     test_window_tree(parent, complex_style, complex_order_3, 3);
1283     test_window_tree(parent, complex_style, complex_order_4, 4);
1284     test_window_tree(parent, complex_style, complex_order_5, 5);
1285 }
1286
1287 static void test_SetFocus(HWND hwnd)
1288 {
1289     HWND child;
1290
1291     /* check if we can set focus to non-visible windows */
1292
1293     ShowWindow(hwnd, SW_SHOW);
1294     SetFocus(0);
1295     SetFocus(hwnd);
1296     ok( GetFocus() == hwnd, "Failed to set focus to visible window %p\n", hwnd );
1297     ok( GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE, "Window %p not visible\n", hwnd );
1298     ShowWindow(hwnd, SW_HIDE);
1299     SetFocus(0);
1300     SetFocus(hwnd);
1301     ok( GetFocus() == hwnd, "Failed to set focus to invisible window %p\n", hwnd );
1302     ok( !(GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE), "Window %p still visible\n", hwnd );
1303     child = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, hwnd, 0, 0, NULL);
1304     assert(child);
1305     SetFocus(child);
1306     ok( GetFocus() == child, "Failed to set focus to invisible child %p\n", child );
1307     ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
1308     ShowWindow(child, SW_SHOW);
1309     ok( GetWindowLong(child,GWL_STYLE) & WS_VISIBLE, "Child %p is not visible\n", child );
1310     ok( GetFocus() == child, "Focus no longer on child %p\n", child );
1311     ShowWindow(child, SW_HIDE);
1312     ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
1313     ok( GetFocus() == hwnd, "Focus should be on parent %p, not %p\n", hwnd, GetFocus() );
1314     ShowWindow(child, SW_SHOW);
1315     SetFocus(child);
1316     ok( GetFocus() == child, "Focus should be on child %p\n", child );
1317     SetWindowPos(child,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW);
1318     ok( GetFocus() == child, "Focus should still be on child %p\n", child );
1319     DestroyWindow( child );
1320 }
1321
1322 START_TEST(win)
1323 {
1324     pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
1325
1326     if (!RegisterWindowClasses()) assert(0);
1327
1328     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
1329     assert(hhook);
1330
1331     hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
1332                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1333                                WS_MAXIMIZEBOX | WS_POPUP,
1334                                100, 100, 200, 200,
1335                                0, 0, 0, NULL);
1336     hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2",
1337                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1338                                 WS_MAXIMIZEBOX | WS_POPUP,
1339                                 100, 100, 200, 200,
1340                                 0, 0, 0, NULL);
1341     assert( hwndMain );
1342     assert( hwndMain2 );
1343
1344     test_parent_owner();
1345     test_shell_window();
1346
1347     test_mdi();
1348     test_icons();
1349     test_SetWindowPos(hwndMain);
1350     test_SetMenu(hwndMain);
1351     test_SetFocus(hwndMain);
1352
1353     test_children_zorder(hwndMain);
1354
1355     UnhookWindowsHookEx(hhook);
1356 }