INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31
32 #include "wine/test.h"
33
34 #ifndef SPI_GETDESKWALLPAPER
35 #define SPI_GETDESKWALLPAPER 0x0073
36 #endif
37
38 #define LONG_PTR INT_PTR
39 #define ULONG_PTR UINT_PTR
40
41 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
42
43 static HWND hwndMain, hwndMain2;
44 static HHOOK hhook;
45
46 /* check the values returned by the various parent/owner functions on a given window */
47 static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent,
48                            HWND gw_owner, HWND ga_root, HWND ga_root_owner )
49 {
50     HWND res;
51
52     if (pGetAncestor)
53     {
54         res = pGetAncestor( hwnd, GA_PARENT );
55         ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p", res, ga_parent );
56     }
57     res = (HWND)GetWindowLongA( hwnd, GWL_HWNDPARENT );
58     ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %p expected %p", res, gwl_parent );
59     res = GetParent( hwnd );
60     ok( res == get_parent, "Wrong result for GetParent %p expected %p", res, get_parent );
61     res = GetWindow( hwnd, GW_OWNER );
62     ok( res == gw_owner, "Wrong result for GW_OWNER %p expected %p", res, gw_owner );
63     if (pGetAncestor)
64     {
65         res = pGetAncestor( hwnd, GA_ROOT );
66         ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p", res, ga_root );
67         res = pGetAncestor( hwnd, GA_ROOTOWNER );
68         ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p", res, ga_root_owner );
69     }
70 }
71
72
73 static HWND create_tool_window( LONG style, HWND parent )
74 {
75     HWND ret = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", style,
76                                0, 0, 100, 100, parent, 0, 0, NULL );
77     ok( ret != 0, "Creation failed" );
78     return ret;
79 }
80
81 /* test parent and owner values for various combinations */
82 static void test_parent_owner(void)
83 {
84     LONG style;
85     HWND test, owner, ret;
86     HWND desktop = GetDesktopWindow();
87     HWND child = create_tool_window( WS_CHILD, hwndMain );
88
89     trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child );
90
91     /* child without parent, should fail */
92     test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1",
93                            WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL );
94     ok( !test, "WS_CHILD without parent created" );
95
96     /* desktop window */
97     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
98     style = GetWindowLongA( desktop, GWL_STYLE );
99     ok( !SetWindowLongA( desktop, GWL_STYLE, WS_POPUP ), "Set GWL_STYLE on desktop succeeded" );
100     ok( !SetWindowLongA( desktop, GWL_STYLE, 0 ), "Set GWL_STYLE on desktop succeeded" );
101     ok( GetWindowLongA( desktop, GWL_STYLE ) == style, "Desktop style changed" );
102
103     /* normal child window */
104     test = create_tool_window( WS_CHILD, hwndMain );
105     trace( "created child %p\n", test );
106     check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain );
107     SetWindowLongA( test, GWL_STYLE, 0 );
108     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
109     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
110     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
111     SetWindowLongA( test, GWL_STYLE, WS_POPUP|WS_CHILD );
112     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
113     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
114     DestroyWindow( test );
115
116     /* normal child window with WS_MAXIMIZE */
117     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, hwndMain );
118     DestroyWindow( test );
119
120     /* normal child window with WS_THICKFRAME */
121     test = create_tool_window( WS_CHILD | WS_THICKFRAME, hwndMain );
122     DestroyWindow( test );
123
124     /* popup window with WS_THICKFRAME */
125     test = create_tool_window( WS_POPUP | WS_THICKFRAME, hwndMain );
126     DestroyWindow( test );
127
128     /* child of desktop */
129     test = create_tool_window( WS_CHILD, desktop );
130     trace( "created child of desktop %p\n", test );
131     check_parents( test, desktop, 0, desktop, 0, test, desktop );
132     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
133     check_parents( test, desktop, 0, 0, 0, test, test );
134     SetWindowLongA( test, GWL_STYLE, 0 );
135     check_parents( test, desktop, 0, 0, 0, test, test );
136     DestroyWindow( test );
137
138     /* child of desktop with WS_MAXIMIZE */
139     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, desktop );
140     DestroyWindow( test );
141
142     /* child of desktop with WS_MINIMIZE */
143     test = create_tool_window( WS_CHILD | WS_MINIMIZE, desktop );
144     DestroyWindow( test );
145
146     /* child of child */
147     test = create_tool_window( WS_CHILD, child );
148     trace( "created child of child %p\n", test );
149     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
150     SetWindowLongA( test, GWL_STYLE, 0 );
151     check_parents( test, child, child, 0, 0, hwndMain, test );
152     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
153     check_parents( test, child, child, 0, 0, hwndMain, test );
154     DestroyWindow( test );
155
156     /* child of child with WS_MAXIMIZE */
157     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, child );
158     DestroyWindow( test );
159
160     /* child of child with WS_MINIMIZE */
161     test = create_tool_window( WS_CHILD | WS_MINIMIZE, child );
162     DestroyWindow( test );
163
164     /* not owned top-level window */
165     test = create_tool_window( 0, 0 );
166     trace( "created top-level %p\n", test );
167     check_parents( test, desktop, 0, 0, 0, test, test );
168     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
169     check_parents( test, desktop, 0, 0, 0, test, test );
170     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
171     check_parents( test, desktop, 0, desktop, 0, test, desktop );
172     DestroyWindow( test );
173
174     /* not owned top-level window with WS_MAXIMIZE */
175     test = create_tool_window( WS_MAXIMIZE, 0 );
176     DestroyWindow( test );
177
178     /* owned top-level window */
179     test = create_tool_window( 0, hwndMain );
180     trace( "created owned top-level %p\n", test );
181     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
182     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
183     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
184     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
185     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
186     DestroyWindow( test );
187
188     /* owned top-level window with WS_MAXIMIZE */
189     test = create_tool_window( WS_MAXIMIZE, hwndMain );
190     DestroyWindow( test );
191
192     /* not owned popup */
193     test = create_tool_window( WS_POPUP, 0 );
194     trace( "created popup %p\n", test );
195     check_parents( test, desktop, 0, 0, 0, test, test );
196     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
197     check_parents( test, desktop, 0, desktop, 0, test, desktop );
198     SetWindowLongA( test, GWL_STYLE, 0 );
199     check_parents( test, desktop, 0, 0, 0, test, test );
200     DestroyWindow( test );
201
202     /* not owned popup with WS_MAXIMIZE */
203     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, 0 );
204     DestroyWindow( test );
205
206     /* owned popup */
207     test = create_tool_window( WS_POPUP, hwndMain );
208     trace( "created owned popup %p\n", test );
209     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
210     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
211     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
212     SetWindowLongA( test, GWL_STYLE, 0 );
213     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
214     DestroyWindow( test );
215
216     /* owned popup with WS_MAXIMIZE */
217     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, hwndMain );
218     DestroyWindow( test );
219
220     /* top-level window owned by child (same as owned by top-level) */
221     test = create_tool_window( 0, child );
222     trace( "created top-level owned by child %p\n", test );
223     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
224     DestroyWindow( test );
225
226     /* top-level window owned by child (same as owned by top-level) with WS_MAXIMIZE */
227     test = create_tool_window( WS_MAXIMIZE, child );
228     DestroyWindow( test );
229
230     /* popup owned by desktop (same as not owned) */
231     test = create_tool_window( WS_POPUP, desktop );
232     trace( "created popup owned by desktop %p\n", test );
233     check_parents( test, desktop, 0, 0, 0, test, test );
234     DestroyWindow( test );
235
236     /* popup owned by desktop (same as not owned) with WS_MAXIMIZE */
237     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, desktop );
238     DestroyWindow( test );
239
240     /* popup owned by child (same as owned by top-level) */
241     test = create_tool_window( WS_POPUP, child );
242     trace( "created popup owned by child %p\n", test );
243     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
244     DestroyWindow( test );
245
246     /* popup owned by child (same as owned by top-level) with WS_MAXIMIZE */
247     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, child );
248     DestroyWindow( test );
249
250     /* not owned popup with WS_CHILD (same as WS_POPUP only) */
251     test = create_tool_window( WS_POPUP | WS_CHILD, 0 );
252     trace( "created WS_CHILD popup %p\n", test );
253     check_parents( test, desktop, 0, 0, 0, test, test );
254     DestroyWindow( test );
255
256     /* not owned popup with WS_CHILD | WS_MAXIMIZE (same as WS_POPUP only) */
257     test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, 0 );
258     DestroyWindow( test );
259
260     /* owned popup with WS_CHILD (same as WS_POPUP only) */
261     test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain );
262     trace( "created owned WS_CHILD popup %p\n", test );
263     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
264     DestroyWindow( test );
265
266     /* owned popup with WS_CHILD (same as WS_POPUP only) with WS_MAXIMIZE */
267     test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, hwndMain );
268     DestroyWindow( test );
269
270     /******************** parent changes *************************/
271     trace( "testing parent changes\n" );
272
273     /* desktop window */
274     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
275 #if 0 /* this test succeeds on NT but crashes on win9x systems */
276     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
277     ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop" );
278     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
279     ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop" );
280     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
281 #endif
282     /* normal child window */
283     test = create_tool_window( WS_CHILD, hwndMain );
284     trace( "created child %p\n", test );
285
286     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
287     ok( ret == hwndMain, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain );
288     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
289
290     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
291     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 );
292     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
293
294     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)desktop );
295     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
296     check_parents( test, desktop, 0, desktop, 0, test, desktop );
297
298     /* window is now child of desktop so GWL_HWNDPARENT changes owner from now on */
299     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
300     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
301     check_parents( test, desktop, child, desktop, child, test, desktop );
302
303     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
304     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
305     check_parents( test, desktop, 0, desktop, 0, test, desktop );
306     DestroyWindow( test );
307
308     /* not owned top-level window */
309     test = create_tool_window( 0, 0 );
310     trace( "created top-level %p\n", test );
311
312     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
313     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
314     check_parents( test, desktop, hwndMain2, 0, hwndMain2, test, test );
315
316     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
317     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 );
318     check_parents( test, desktop, child, 0, child, test, test );
319
320     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
321     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
322     check_parents( test, desktop, 0, 0, 0, test, test );
323     DestroyWindow( test );
324
325     /* not owned popup */
326     test = create_tool_window( WS_POPUP, 0 );
327     trace( "created popup %p\n", test );
328
329     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
330     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
331     check_parents( test, desktop, hwndMain2, hwndMain2, hwndMain2, test, hwndMain2 );
332
333     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
334     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 );
335     check_parents( test, desktop, child, child, child, test, hwndMain );
336
337     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
338     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
339     check_parents( test, desktop, 0, 0, 0, test, test );
340     DestroyWindow( test );
341
342     /* normal child window */
343     test = create_tool_window( WS_CHILD, hwndMain );
344     trace( "created child %p\n", test );
345
346     ret = SetParent( test, desktop );
347     ok( ret == hwndMain, "SetParent return value %p expected %p", ret, hwndMain );
348     check_parents( test, desktop, 0, desktop, 0, test, desktop );
349
350     ret = SetParent( test, child );
351     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
352     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
353
354     ret = SetParent( test, hwndMain2 );
355     ok( ret == child, "SetParent return value %p expected %p", ret, child );
356     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
357     DestroyWindow( test );
358
359     /* not owned top-level window */
360     test = create_tool_window( 0, 0 );
361     trace( "created top-level %p\n", test );
362
363     ret = SetParent( test, child );
364     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
365     check_parents( test, child, child, 0, 0, hwndMain, test );
366     DestroyWindow( test );
367
368     /* owned popup */
369     test = create_tool_window( WS_POPUP, hwndMain2 );
370     trace( "created owned popup %p\n", test );
371
372     ret = SetParent( test, child );
373     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
374     check_parents( test, child, child, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
375
376     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)hwndMain );
377     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
378     check_parents( test, hwndMain, hwndMain, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
379     DestroyWindow( test );
380
381     /**************** test owner destruction *******************/
382
383     /* owned child popup */
384     owner = create_tool_window( 0, 0 );
385     test = create_tool_window( WS_POPUP, owner );
386     trace( "created owner %p and popup %p\n", owner, test );
387     ret = SetParent( test, child );
388     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
389     check_parents( test, child, child, owner, owner, hwndMain, owner );
390     /* window is now child of 'child' but owned by 'owner' */
391     DestroyWindow( owner );
392     ok( IsWindow(test), "Window %p destroyed by owner destruction", test );
393     check_parents( test, child, child, owner, owner, hwndMain, owner );
394     ok( !IsWindow(owner), "Owner %p not destroyed", owner );
395     DestroyWindow(test);
396
397     /* owned top-level popup */
398     owner = create_tool_window( 0, 0 );
399     test = create_tool_window( WS_POPUP, owner );
400     trace( "created owner %p and popup %p\n", owner, test );
401     check_parents( test, desktop, owner, owner, owner, test, owner );
402     DestroyWindow( owner );
403     ok( !IsWindow(test), "Window %p not destroyed by owner destruction", test );
404
405     /* top-level popup owned by child */
406     owner = create_tool_window( WS_CHILD, hwndMain2 );
407     test = create_tool_window( WS_POPUP, 0 );
408     trace( "created owner %p and popup %p\n", owner, test );
409     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)owner );
410     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
411     check_parents( test, desktop, owner, owner, owner, test, hwndMain2 );
412     DestroyWindow( owner );
413     ok( IsWindow(test), "Window %p destroyed by owner destruction", test );
414     ok( !IsWindow(owner), "Owner %p not destroyed", owner );
415     check_parents( test, desktop, owner, owner, owner, test, owner );
416     DestroyWindow(test);
417
418     /* final cleanup */
419     DestroyWindow(child);
420 }
421
422
423 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
424 {
425     switch (msg)
426     {
427         case WM_GETMINMAXINFO:
428         {
429             MINMAXINFO* minmax = (MINMAXINFO *)lparam;
430
431             trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam);
432             trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n"
433                   "       ptMinTrackSize (%ld,%ld), ptMaxTrackSize (%ld,%ld)\n",
434                   minmax->ptReserved.x, minmax->ptReserved.y,
435                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
436                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
437                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
438                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
439             SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021);
440             break;
441         }
442         case WM_NCCREATE:
443         {
444             BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021;
445             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
446
447             trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style);
448             if (got_getminmaxinfo)
449                 trace("%p got WM_GETMINMAXINFO\n", hwnd);
450
451             if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
452                 ok(got_getminmaxinfo, "main: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
453             else
454                 ok(!got_getminmaxinfo, "main: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
455             break;
456         }
457     }
458
459     return DefWindowProcA(hwnd, msg, wparam, lparam);
460 }
461
462 static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
463 {
464     switch (msg)
465     {
466         case WM_GETMINMAXINFO:
467         {
468             MINMAXINFO* minmax = (MINMAXINFO *)lparam;
469
470             trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam);
471             trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n"
472                   "       ptMinTrackSize (%ld,%ld), ptMaxTrackSize (%ld,%ld)\n",
473                   minmax->ptReserved.x, minmax->ptReserved.y,
474                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
475                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
476                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
477                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
478             SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021);
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, "tool: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
492             else
493                 ok(!got_getminmaxinfo, "tool: 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 BOOL RegisterWindowClasses(void)
502 {
503     WNDCLASSA cls;
504
505     cls.style = 0;
506     cls.lpfnWndProc = main_window_procA;
507     cls.cbClsExtra = 0;
508     cls.cbWndExtra = 0;
509     cls.hInstance = GetModuleHandleA(0);
510     cls.hIcon = 0;
511     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
512     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
513     cls.lpszMenuName = NULL;
514     cls.lpszClassName = "MainWindowClass";
515
516     if(!RegisterClassA(&cls)) return FALSE;
517
518     cls.style = 0;
519     cls.lpfnWndProc = tool_window_procA;
520     cls.cbClsExtra = 0;
521     cls.cbWndExtra = 0;
522     cls.hInstance = GetModuleHandleA(0);
523     cls.hIcon = 0;
524     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
525     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
526     cls.lpszMenuName = NULL;
527     cls.lpszClassName = "ToolWindowClass";
528
529     if(!RegisterClassA(&cls)) return FALSE;
530
531     return TRUE;
532 }
533
534 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
535
536     static const char *CBT_code_name[10] = {
537         "HCBT_MOVESIZE",
538         "HCBT_MINMAX",
539         "HCBT_QS",
540         "HCBT_CREATEWND",
541         "HCBT_DESTROYWND",
542         "HCBT_ACTIVATE",
543         "HCBT_CLICKSKIPPED",
544         "HCBT_KEYSKIPPED",
545         "HCBT_SYSCOMMAND",
546         "HCBT_SETFOCUS" };
547     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
548
549     trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam);
550
551     switch (nCode)
552     {
553         case HCBT_CREATEWND:
554         {
555             CBT_CREATEWNDA *createwnd = (CBT_CREATEWNDA *)lParam;
556             trace("HCBT_CREATEWND: hwnd %p, parent %p, style %08lx\n",
557                   (HWND)wParam, createwnd->lpcs->hwndParent, createwnd->lpcs->style);
558             ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n");
559             break;
560         }
561     }
562
563     return CallNextHookEx(hhook, nCode, wParam, lParam);
564 }
565
566 static void test_shell_window()
567 {
568     BOOL ret;
569     DWORD error;
570     HMODULE hinst, hUser32;
571     BOOL (WINAPI*SetShellWindow)(HWND);
572     BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
573     HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5;
574     HWND shellWindow, nextWnd;
575
576     shellWindow = GetShellWindow();
577     hinst = GetModuleHandle(0);
578     hUser32 = GetModuleHandleA("user32");
579
580     SetShellWindow = (void *)GetProcAddress(hUser32, "SetShellWindow");
581     SetShellWindowEx = (void *)GetProcAddress(hUser32, "SetShellWindowEx");
582
583     trace("previous shell window: %p\n", shellWindow);
584
585     if (shellWindow) {
586         DWORD pid;
587         HANDLE hProcess;
588
589         ret = DestroyWindow(shellWindow);
590         error = GetLastError();
591
592         ok(!ret, "DestroyWindow(shellWindow)\n");
593         /* passes on Win XP, but not on Win98
594         ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n"); */
595
596         /* close old shell instance */
597         GetWindowThreadProcessId(shellWindow, &pid);
598         hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
599         ret = TerminateProcess(hProcess, 0);
600         ok(ret, "termination of previous shell process failed: GetLastError()=%ld", GetLastError());
601         WaitForSingleObject(hProcess, INFINITE);    /* wait for termination */
602         CloseHandle(hProcess);
603     }
604
605     hwnd1 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0);
606     trace("created window 1: %p\n", hwnd1);
607
608     ret = SetShellWindow(hwnd1);
609     ok(ret, "first call to SetShellWindow(hwnd1)\n");
610     shellWindow = GetShellWindow();
611     ok(shellWindow==hwnd1, "wrong shell window: %p", shellWindow);
612
613     ret = SetShellWindow(hwnd1);
614     ok(!ret, "second call to SetShellWindow(hwnd1)\n");
615
616     ret = SetShellWindow(0);
617     error = GetLastError();
618     /* passes on Win XP, but not on Win98
619     ok(!ret, "reset shell window by SetShellWindow(0)\n");
620     ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */
621
622     ret = SetShellWindow(hwnd1);
623     /* passes on Win XP, but not on Win98
624     ok(!ret, "third call to SetShellWindow(hwnd1)\n"); */
625
626     todo_wine
627     {
628         SetWindowLong(hwnd1, GWL_EXSTYLE, GetWindowLong(hwnd1,GWL_EXSTYLE)|WS_EX_TOPMOST);
629         ret = GetWindowLong(hwnd1,GWL_EXSTYLE)&WS_EX_TOPMOST? TRUE: FALSE;
630         ok(!ret, "SetWindowExStyle(hwnd1, WS_EX_TOPMOST)\n");
631     }
632
633     ret = DestroyWindow(hwnd1);
634     ok(ret, "DestroyWindow(hwnd1)\n");
635
636     hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0);
637     trace("created window 2: %p\n", hwnd2);
638     ret = SetShellWindow(hwnd2);
639     ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST");
640
641     hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0);
642     trace("created window 3: %p\n", hwnd3);
643
644     hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0);
645     trace("created window 4: %p\n", hwnd4);
646
647     nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
648     ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd);
649
650     ret = SetShellWindow(hwnd4);
651     ok(ret, "SetShellWindow(hwnd4)\n");
652     shellWindow = GetShellWindow();
653     ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4", shellWindow);
654
655     nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
656     ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd);
657
658     ret = SetWindowPos(hwnd4, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
659     ok(ret, "SetWindowPos(hwnd4, HWND_TOPMOST)\n");
660
661     ret = SetWindowPos(hwnd4, hwnd3, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
662     ok(ret, "SetWindowPos(hwnd4, hwnd3");
663
664     ret = SetShellWindow(hwnd3);
665     ok(!ret, "SetShellWindow(hwnd3)\n");
666     shellWindow = GetShellWindow();
667     ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4", shellWindow);
668
669     hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0);
670     trace("created window 5: %p\n", hwnd5);
671     ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
672     ok(ret, "SetWindowPos(hwnd4, hwnd5)\n");
673
674     todo_wine
675     {
676         nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
677         ok(nextWnd==0, "wrong next window for hwnd4 after SetWindowPos(): %p - expected 0\n", nextWnd);
678     }
679
680     /* destroy test windows */
681     DestroyWindow(hwnd2);
682     DestroyWindow(hwnd3);
683     DestroyWindow(hwnd4);
684     DestroyWindow(hwnd5);
685 }
686
687
688 START_TEST(win)
689 {
690     pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
691
692     if (!RegisterWindowClasses()) assert(0);
693
694     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
695     assert(hhook);
696
697     hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
698                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
699                                WS_MAXIMIZEBOX | WS_POPUP,
700                                100, 100, 200, 200,
701                                0, 0, 0, NULL);
702     hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2",
703                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
704                                 WS_MAXIMIZEBOX | WS_POPUP,
705                                 100, 100, 200, 200,
706                                 0, 0, 0, NULL);
707     assert( hwndMain );
708     assert( hwndMain2 );
709
710     test_parent_owner();
711     test_shell_window();
712     UnhookWindowsHookEx(hhook);
713 }