Implements OleLoadPicturePath.
[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 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38
39 #include "wine/test.h"
40
41 #ifndef SPI_GETDESKWALLPAPER
42 #define SPI_GETDESKWALLPAPER 0x0073
43 #endif
44
45 #define LONG_PTR INT_PTR
46 #define ULONG_PTR UINT_PTR
47
48 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
49 static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*);
50
51 static HWND hwndMessage;
52 static HWND hwndMain, hwndMain2;
53 static HHOOK hhook;
54
55 /* check the values returned by the various parent/owner functions on a given window */
56 static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent,
57                            HWND gw_owner, HWND ga_root, HWND ga_root_owner )
58 {
59     HWND res;
60
61     if (pGetAncestor)
62     {
63         res = pGetAncestor( hwnd, GA_PARENT );
64         ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p\n", res, ga_parent );
65     }
66     res = (HWND)GetWindowLongA( hwnd, GWL_HWNDPARENT );
67     ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %p expected %p\n", res, gwl_parent );
68     res = GetParent( hwnd );
69     ok( res == get_parent, "Wrong result for GetParent %p expected %p\n", res, get_parent );
70     res = GetWindow( hwnd, GW_OWNER );
71     ok( res == gw_owner, "Wrong result for GW_OWNER %p expected %p\n", res, gw_owner );
72     if (pGetAncestor)
73     {
74         res = pGetAncestor( hwnd, GA_ROOT );
75         ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p\n", res, ga_root );
76         res = pGetAncestor( hwnd, GA_ROOTOWNER );
77         ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p\n", res, ga_root_owner );
78     }
79 }
80
81
82 static HWND create_tool_window( LONG style, HWND parent )
83 {
84     HWND ret = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", style,
85                                0, 0, 100, 100, parent, 0, 0, NULL );
86     ok( ret != 0, "Creation failed\n" );
87     return ret;
88 }
89
90 /* test parent and owner values for various combinations */
91 static void test_parent_owner(void)
92 {
93     LONG style;
94     HWND test, owner, ret;
95     HWND desktop = GetDesktopWindow();
96     HWND child = create_tool_window( WS_CHILD, hwndMain );
97
98     trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child );
99
100     /* child without parent, should fail */
101     test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1",
102                            WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL );
103     ok( !test, "WS_CHILD without parent created\n" );
104
105     /* desktop window */
106     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
107     style = GetWindowLongA( desktop, GWL_STYLE );
108     ok( !SetWindowLongA( desktop, GWL_STYLE, WS_POPUP ), "Set GWL_STYLE on desktop succeeded\n" );
109     ok( !SetWindowLongA( desktop, GWL_STYLE, 0 ), "Set GWL_STYLE on desktop succeeded\n" );
110     ok( GetWindowLongA( desktop, GWL_STYLE ) == style, "Desktop style changed\n" );
111
112     /* normal child window */
113     test = create_tool_window( WS_CHILD, hwndMain );
114     trace( "created child %p\n", test );
115     check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain );
116     SetWindowLongA( test, GWL_STYLE, 0 );
117     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
118     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
119     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
120     SetWindowLongA( test, GWL_STYLE, WS_POPUP|WS_CHILD );
121     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
122     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
123     DestroyWindow( test );
124
125     /* normal child window with WS_MAXIMIZE */
126     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, hwndMain );
127     DestroyWindow( test );
128
129     /* normal child window with WS_THICKFRAME */
130     test = create_tool_window( WS_CHILD | WS_THICKFRAME, hwndMain );
131     DestroyWindow( test );
132
133     /* popup window with WS_THICKFRAME */
134     test = create_tool_window( WS_POPUP | WS_THICKFRAME, hwndMain );
135     DestroyWindow( test );
136
137     /* child of desktop */
138     test = create_tool_window( WS_CHILD, desktop );
139     trace( "created child of desktop %p\n", test );
140     check_parents( test, desktop, 0, desktop, 0, test, desktop );
141     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
142     check_parents( test, desktop, 0, 0, 0, test, test );
143     SetWindowLongA( test, GWL_STYLE, 0 );
144     check_parents( test, desktop, 0, 0, 0, test, test );
145     DestroyWindow( test );
146
147     /* child of desktop with WS_MAXIMIZE */
148     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, desktop );
149     DestroyWindow( test );
150
151     /* child of desktop with WS_MINIMIZE */
152     test = create_tool_window( WS_CHILD | WS_MINIMIZE, desktop );
153     DestroyWindow( test );
154
155     /* child of child */
156     test = create_tool_window( WS_CHILD, child );
157     trace( "created child of child %p\n", test );
158     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
159     SetWindowLongA( test, GWL_STYLE, 0 );
160     check_parents( test, child, child, 0, 0, hwndMain, test );
161     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
162     check_parents( test, child, child, 0, 0, hwndMain, test );
163     DestroyWindow( test );
164
165     /* child of child with WS_MAXIMIZE */
166     test = create_tool_window( WS_CHILD | WS_MAXIMIZE, child );
167     DestroyWindow( test );
168
169     /* child of child with WS_MINIMIZE */
170     test = create_tool_window( WS_CHILD | WS_MINIMIZE, child );
171     DestroyWindow( test );
172
173     /* not owned top-level window */
174     test = create_tool_window( 0, 0 );
175     trace( "created top-level %p\n", test );
176     check_parents( test, desktop, 0, 0, 0, test, test );
177     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
178     check_parents( test, desktop, 0, 0, 0, test, test );
179     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
180     check_parents( test, desktop, 0, desktop, 0, test, desktop );
181     DestroyWindow( test );
182
183     /* not owned top-level window with WS_MAXIMIZE */
184     test = create_tool_window( WS_MAXIMIZE, 0 );
185     DestroyWindow( test );
186
187     /* owned top-level window */
188     test = create_tool_window( 0, hwndMain );
189     trace( "created owned top-level %p\n", test );
190     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
191     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
192     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
193     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
194     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
195     DestroyWindow( test );
196
197     /* owned top-level window with WS_MAXIMIZE */
198     test = create_tool_window( WS_MAXIMIZE, hwndMain );
199     DestroyWindow( test );
200
201     /* not owned popup */
202     test = create_tool_window( WS_POPUP, 0 );
203     trace( "created popup %p\n", test );
204     check_parents( test, desktop, 0, 0, 0, test, test );
205     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
206     check_parents( test, desktop, 0, desktop, 0, test, desktop );
207     SetWindowLongA( test, GWL_STYLE, 0 );
208     check_parents( test, desktop, 0, 0, 0, test, test );
209     DestroyWindow( test );
210
211     /* not owned popup with WS_MAXIMIZE */
212     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, 0 );
213     DestroyWindow( test );
214
215     /* owned popup */
216     test = create_tool_window( WS_POPUP, hwndMain );
217     trace( "created owned popup %p\n", test );
218     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
219     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
220     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
221     SetWindowLongA( test, GWL_STYLE, 0 );
222     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
223     DestroyWindow( test );
224
225     /* owned popup with WS_MAXIMIZE */
226     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, hwndMain );
227     DestroyWindow( test );
228
229     /* top-level window owned by child (same as owned by top-level) */
230     test = create_tool_window( 0, child );
231     trace( "created top-level owned by child %p\n", test );
232     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
233     DestroyWindow( test );
234
235     /* top-level window owned by child (same as owned by top-level) with WS_MAXIMIZE */
236     test = create_tool_window( WS_MAXIMIZE, child );
237     DestroyWindow( test );
238
239     /* popup owned by desktop (same as not owned) */
240     test = create_tool_window( WS_POPUP, desktop );
241     trace( "created popup owned by desktop %p\n", test );
242     check_parents( test, desktop, 0, 0, 0, test, test );
243     DestroyWindow( test );
244
245     /* popup owned by desktop (same as not owned) with WS_MAXIMIZE */
246     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, desktop );
247     DestroyWindow( test );
248
249     /* popup owned by child (same as owned by top-level) */
250     test = create_tool_window( WS_POPUP, child );
251     trace( "created popup owned by child %p\n", test );
252     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
253     DestroyWindow( test );
254
255     /* popup owned by child (same as owned by top-level) with WS_MAXIMIZE */
256     test = create_tool_window( WS_POPUP | WS_MAXIMIZE, child );
257     DestroyWindow( test );
258
259     /* not owned popup with WS_CHILD (same as WS_POPUP only) */
260     test = create_tool_window( WS_POPUP | WS_CHILD, 0 );
261     trace( "created WS_CHILD popup %p\n", test );
262     check_parents( test, desktop, 0, 0, 0, test, test );
263     DestroyWindow( test );
264
265     /* not owned popup with WS_CHILD | WS_MAXIMIZE (same as WS_POPUP only) */
266     test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, 0 );
267     DestroyWindow( test );
268
269     /* owned popup with WS_CHILD (same as WS_POPUP only) */
270     test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain );
271     trace( "created owned WS_CHILD popup %p\n", test );
272     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
273     DestroyWindow( test );
274
275     /* owned popup with WS_CHILD (same as WS_POPUP only) with WS_MAXIMIZE */
276     test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, hwndMain );
277     DestroyWindow( test );
278
279     /******************** parent changes *************************/
280     trace( "testing parent changes\n" );
281
282     /* desktop window */
283     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
284 #if 0 /* this test succeeds on NT but crashes on win9x systems */
285     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
286     ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop\n" );
287     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
288     ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop\n" );
289     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
290 #endif
291     /* normal child window */
292     test = create_tool_window( WS_CHILD, hwndMain );
293     trace( "created child %p\n", test );
294
295     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
296     ok( ret == hwndMain, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain );
297     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
298
299     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
300     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain2 );
301     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
302
303     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)desktop );
304     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
305     check_parents( test, desktop, 0, desktop, 0, test, desktop );
306
307     /* window is now child of desktop so GWL_HWNDPARENT changes owner from now on */
308     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
309     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
310     check_parents( test, desktop, child, desktop, child, test, desktop );
311
312     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
313     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
314     check_parents( test, desktop, 0, desktop, 0, test, desktop );
315     DestroyWindow( test );
316
317     /* not owned top-level window */
318     test = create_tool_window( 0, 0 );
319     trace( "created top-level %p\n", test );
320
321     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
322     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
323     check_parents( test, desktop, hwndMain2, 0, hwndMain2, test, test );
324
325     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
326     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain2 );
327     check_parents( test, desktop, child, 0, child, test, test );
328
329     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
330     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
331     check_parents( test, desktop, 0, 0, 0, test, test );
332     DestroyWindow( test );
333
334     /* not owned popup */
335     test = create_tool_window( WS_POPUP, 0 );
336     trace( "created popup %p\n", test );
337
338     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
339     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
340     check_parents( test, desktop, hwndMain2, hwndMain2, hwndMain2, test, hwndMain2 );
341
342     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
343     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain2 );
344     check_parents( test, desktop, child, child, child, test, hwndMain );
345
346     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
347     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
348     check_parents( test, desktop, 0, 0, 0, test, test );
349     DestroyWindow( test );
350
351     /* normal child window */
352     test = create_tool_window( WS_CHILD, hwndMain );
353     trace( "created child %p\n", test );
354
355     ret = SetParent( test, desktop );
356     ok( ret == hwndMain, "SetParent return value %p expected %p\n", ret, hwndMain );
357     check_parents( test, desktop, 0, desktop, 0, test, desktop );
358
359     ret = SetParent( test, child );
360     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
361     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
362
363     ret = SetParent( test, hwndMain2 );
364     ok( ret == child, "SetParent return value %p expected %p\n", ret, child );
365     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
366     DestroyWindow( test );
367
368     /* not owned top-level window */
369     test = create_tool_window( 0, 0 );
370     trace( "created top-level %p\n", test );
371
372     ret = SetParent( test, child );
373     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
374     check_parents( test, child, child, 0, 0, hwndMain, test );
375     DestroyWindow( test );
376
377     /* owned popup */
378     test = create_tool_window( WS_POPUP, hwndMain2 );
379     trace( "created owned popup %p\n", test );
380
381     ret = SetParent( test, child );
382     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
383     check_parents( test, child, child, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
384
385     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)hwndMain );
386     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p\n", ret, child );
387     check_parents( test, hwndMain, hwndMain, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
388     DestroyWindow( test );
389
390     /**************** test owner destruction *******************/
391
392     /* owned child popup */
393     owner = create_tool_window( 0, 0 );
394     test = create_tool_window( WS_POPUP, owner );
395     trace( "created owner %p and popup %p\n", owner, test );
396     ret = SetParent( test, child );
397     ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop );
398     check_parents( test, child, child, owner, owner, hwndMain, owner );
399     /* window is now child of 'child' but owned by 'owner' */
400     DestroyWindow( owner );
401     ok( IsWindow(test), "Window %p destroyed by owner destruction\n", test );
402     /* Win98 doesn't pass this test. It doesn't allow a destroyed owner,
403      * while Win95, Win2k, WinXP do.
404      */
405     /*check_parents( test, child, child, owner, owner, hwndMain, owner );*/
406     ok( !IsWindow(owner), "Owner %p not destroyed\n", owner );
407     DestroyWindow(test);
408
409     /* owned top-level popup */
410     owner = create_tool_window( 0, 0 );
411     test = create_tool_window( WS_POPUP, owner );
412     trace( "created owner %p and popup %p\n", owner, test );
413     check_parents( test, desktop, owner, owner, owner, test, owner );
414     DestroyWindow( owner );
415     ok( !IsWindow(test), "Window %p not destroyed by owner destruction\n", test );
416
417     /* top-level popup owned by child */
418     owner = create_tool_window( WS_CHILD, hwndMain2 );
419     test = create_tool_window( WS_POPUP, 0 );
420     trace( "created owner %p and popup %p\n", owner, test );
421     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)owner );
422     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret );
423     check_parents( test, desktop, owner, owner, owner, test, hwndMain2 );
424     DestroyWindow( owner );
425     ok( IsWindow(test), "Window %p destroyed by owner destruction\n", test );
426     ok( !IsWindow(owner), "Owner %p not destroyed\n", owner );
427     /* Win98 doesn't pass this test. It doesn't allow a destroyed owner,
428      * while Win95, Win2k, WinXP do.
429      */
430     /*check_parents( test, desktop, owner, owner, owner, test, owner );*/
431     DestroyWindow(test);
432
433     /* final cleanup */
434     DestroyWindow(child);
435 }
436
437
438 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
439 {
440     switch (msg)
441     {
442         case WM_GETMINMAXINFO:
443         {
444             MINMAXINFO* minmax = (MINMAXINFO *)lparam;
445
446             trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam);
447             trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n"
448                   "       ptMinTrackSize (%ld,%ld), ptMaxTrackSize (%ld,%ld)\n",
449                   minmax->ptReserved.x, minmax->ptReserved.y,
450                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
451                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
452                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
453                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
454             SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021);
455             break;
456         }
457         case WM_WINDOWPOSCHANGING:
458         {
459             BOOL is_win9x = GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == 0;
460             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
461             trace("main: WM_WINDOWPOSCHANGING\n");
462             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
463                    winpos->hwnd, winpos->hwndInsertAfter,
464                    winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
465             if (!(winpos->flags & SWP_NOMOVE))
466             {
467                 ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x);
468                 ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y);
469             }
470             /* Win9x does not fixup cx/xy for WM_WINDOWPOSCHANGING */
471             if (!(winpos->flags & SWP_NOSIZE) && !is_win9x)
472             {
473                 ok(winpos->cx >= 0 && winpos->cx <= 32767, "bad winpos->cx %d\n", winpos->cx);
474                 ok(winpos->cy >= 0 && winpos->cy <= 32767, "bad winpos->cy %d\n", winpos->cy);
475             }
476             break;
477         }
478         case WM_WINDOWPOSCHANGED:
479         {
480             RECT rc1, rc2;
481             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
482             trace("main: WM_WINDOWPOSCHANGED\n");
483             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
484                    winpos->hwnd, winpos->hwndInsertAfter,
485                    winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
486             ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x);
487             ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y);
488
489             ok(winpos->cx >= 0 && winpos->cx <= 32767, "bad winpos->cx %d\n", winpos->cx);
490             ok(winpos->cy >= 0 && winpos->cy <= 32767, "bad winpos->cy %d\n", winpos->cy);
491
492             GetWindowRect(hwnd, &rc1);
493             trace("window: (%ld,%ld)-(%ld,%ld)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
494             SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
495             /* note: winpos coordinates are relative to parent */
496             MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
497             trace("pos: (%ld,%ld)-(%ld,%ld)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
498 #if 0 /* Uncomment this once the test succeeds in all cases */
499             ok(EqualRect(&rc1, &rc2), "rects do not match\n");
500 #endif
501
502             GetClientRect(hwnd, &rc2);
503             DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
504             MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
505             ok(EqualRect(&rc1, &rc2), "rects do not match (%ld,%ld-%ld,%ld) / (%ld,%ld-%ld,%ld)\n",
506                rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom );
507             break;
508         }
509         case WM_NCCREATE:
510         {
511             BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021;
512             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
513
514             trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style);
515             if (got_getminmaxinfo)
516                 trace("%p got WM_GETMINMAXINFO\n", hwnd);
517
518             if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
519                 ok(got_getminmaxinfo, "main: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
520             else
521                 ok(!got_getminmaxinfo, "main: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
522             break;
523         }
524     }
525
526     return DefWindowProcA(hwnd, msg, wparam, lparam);
527 }
528
529 static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
530 {
531     switch (msg)
532     {
533         case WM_GETMINMAXINFO:
534         {
535             MINMAXINFO* minmax = (MINMAXINFO *)lparam;
536
537             trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam);
538             trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n"
539                   "       ptMinTrackSize (%ld,%ld), ptMaxTrackSize (%ld,%ld)\n",
540                   minmax->ptReserved.x, minmax->ptReserved.y,
541                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
542                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
543                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
544                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
545             SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021);
546             break;
547         }
548         case WM_NCCREATE:
549         {
550             BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021;
551             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
552
553             trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style);
554             if (got_getminmaxinfo)
555                 trace("%p got WM_GETMINMAXINFO\n", hwnd);
556
557             if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
558                 ok(got_getminmaxinfo, "tool: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
559             else
560                 ok(!got_getminmaxinfo, "tool: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
561             break;
562         }
563     }
564
565     return DefWindowProcA(hwnd, msg, wparam, lparam);
566 }
567
568 static BOOL RegisterWindowClasses(void)
569 {
570     WNDCLASSA cls;
571
572     cls.style = 0;
573     cls.lpfnWndProc = main_window_procA;
574     cls.cbClsExtra = 0;
575     cls.cbWndExtra = 0;
576     cls.hInstance = GetModuleHandleA(0);
577     cls.hIcon = 0;
578     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
579     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
580     cls.lpszMenuName = NULL;
581     cls.lpszClassName = "MainWindowClass";
582
583     if(!RegisterClassA(&cls)) return FALSE;
584
585     cls.style = 0;
586     cls.lpfnWndProc = tool_window_procA;
587     cls.cbClsExtra = 0;
588     cls.cbWndExtra = 0;
589     cls.hInstance = GetModuleHandleA(0);
590     cls.hIcon = 0;
591     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
592     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
593     cls.lpszMenuName = NULL;
594     cls.lpszClassName = "ToolWindowClass";
595
596     if(!RegisterClassA(&cls)) return FALSE;
597
598     return TRUE;
599 }
600
601 static void verify_window_info(HWND hwnd, const WINDOWINFO *info, BOOL test_borders)
602 {
603     RECT rcWindow, rcClient;
604     UINT border;
605     DWORD status;
606
607     ok(IsWindow(hwnd), "bad window handle\n");
608
609     GetWindowRect(hwnd, &rcWindow);
610     ok(EqualRect(&rcWindow, &info->rcWindow), "wrong rcWindow\n");
611
612     GetClientRect(hwnd, &rcClient);
613     /* translate to screen coordinates */
614     MapWindowPoints(hwnd, 0, (LPPOINT)&rcClient, 2);
615     ok(EqualRect(&rcClient, &info->rcClient), "wrong rcClient\n");
616
617     ok(info->dwStyle == (DWORD)GetWindowLongA(hwnd, GWL_STYLE), "wrong dwStyle\n");
618     ok(info->dwExStyle == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE), "wrong dwExStyle\n");
619     status = (GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0;
620     ok(info->dwWindowStatus == status, "wrong dwWindowStatus %04lx/%04lx\n",
621        info->dwWindowStatus, status);
622
623     if (test_borders && !IsRectEmpty(&rcWindow))
624     {
625         trace("rcWindow: %ld,%ld - %ld,%ld\n", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
626         trace("rcClient: %ld,%ld - %ld,%ld\n", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
627
628         ok(info->cxWindowBorders == (unsigned)(rcClient.left - rcWindow.left),
629             "wrong cxWindowBorders %d != %ld\n", info->cxWindowBorders, rcClient.left - rcWindow.left);
630         border = min(rcWindow.bottom - rcClient.bottom, rcClient.top - rcWindow.top);
631         ok(info->cyWindowBorders == border,
632            "wrong cyWindowBorders %d != %d\n", info->cyWindowBorders, border);
633     }
634
635     ok(info->atomWindowType == GetClassLongA(hwnd, GCW_ATOM), "wrong atomWindowType\n");
636     ok(info->wCreatorVersion == 0x0400, "wrong wCreatorVersion %04x\n", info->wCreatorVersion);
637 }
638
639 static void test_nonclient_area(HWND hwnd)
640 {
641     DWORD style, exstyle;
642     RECT rc_window, rc_client, rc;
643     BOOL menu;
644
645     style = GetWindowLongA(hwnd, GWL_STYLE);
646     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
647     menu = !(style & WS_CHILD) && GetMenu(hwnd) != 0;
648
649     GetWindowRect(hwnd, &rc_window);
650     trace("window: (%ld,%ld)-(%ld,%ld)\n", rc_window.left, rc_window.top, rc_window.right, rc_window.bottom);
651     GetClientRect(hwnd, &rc_client);
652     trace("client: (%ld,%ld)-(%ld,%ld)\n", rc_client.left, rc_client.top, rc_client.right, rc_client.bottom);
653
654     /* avoid some cases when things go wrong */
655     if (IsRectEmpty(&rc_window) || IsRectEmpty(&rc_client) ||
656         rc_window.right > 32768 || rc_window.bottom > 32768) return;
657
658     CopyRect(&rc, &rc_client);
659     MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
660     AdjustWindowRectEx(&rc, style, menu, exstyle);
661     trace("calc window: (%ld,%ld)-(%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
662 #if 0 /* Uncomment this once the test succeeds in all cases */
663     ok(EqualRect(&rc, &rc_window), "window rect does not match\n");
664 #endif
665
666     CopyRect(&rc, &rc_window);
667     DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
668     MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2);
669     trace("calc client: (%ld,%ld)-(%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
670 #if 0 /* Uncomment this once the test succeeds in all cases */
671     ok(EqualRect(&rc, &rc_client), "client rect does not match\n");
672 #endif
673
674     /* and now test AdjustWindowRectEx and WM_NCCALCSIZE on synthetic data */
675     SetRect(&rc_client, 0, 0, 250, 150);
676     CopyRect(&rc_window, &rc_client);
677     MapWindowPoints(hwnd, 0, (LPPOINT)&rc_window, 2);
678     AdjustWindowRectEx(&rc_window, style, menu, exstyle);
679     trace("calc window: (%ld,%ld)-(%ld,%ld)\n",
680         rc_window.left, rc_window.top, rc_window.right, rc_window.bottom);
681
682     CopyRect(&rc, &rc_window);
683     DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
684     MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2);
685     trace("calc client: (%ld,%ld)-(%ld,%ld)\n", rc.left, rc.top, rc.right, rc.bottom);
686 #if 0 /* Uncomment this once the test succeeds in all cases */
687     ok(EqualRect(&rc, &rc_client), "client rect does not match\n");
688 #endif
689 }
690
691 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) 
692
693     static const char *CBT_code_name[10] = {
694         "HCBT_MOVESIZE",
695         "HCBT_MINMAX",
696         "HCBT_QS",
697         "HCBT_CREATEWND",
698         "HCBT_DESTROYWND",
699         "HCBT_ACTIVATE",
700         "HCBT_CLICKSKIPPED",
701         "HCBT_KEYSKIPPED",
702         "HCBT_SYSCOMMAND",
703         "HCBT_SETFOCUS" };
704     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
705
706     trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam);
707
708     /* on HCBT_DESTROYWND window state is undefined */
709     if (nCode != HCBT_DESTROYWND && wParam)
710     {
711         BOOL is_win9x = GetWindowLongPtrW((HWND)wParam, GWLP_WNDPROC) == 0;
712         if (is_win9x && nCode == HCBT_CREATEWND)
713             /* Win9x doesn't like WM_NCCALCSIZE with synthetic data and crashes */;
714         else
715             test_nonclient_area((HWND)wParam);
716
717         if (pGetWindowInfo)
718         {
719             WINDOWINFO info;
720
721             /* Win98 actually does check the info.cbSize and doesn't allow
722              * it to be anything except sizeof(WINDOWINFO), while Win95, Win2k,
723              * WinXP do not check it at all.
724              */
725             info.cbSize = sizeof(WINDOWINFO);
726             ok(pGetWindowInfo((HWND)wParam, &info), "GetWindowInfo should not fail\n");
727             /* win2k SP4 returns broken border info if GetWindowInfo
728              * is being called from HCBT_DESTROYWND or HCBT_MINMAX hook proc.
729              */
730             verify_window_info((HWND)wParam, &info, nCode != HCBT_MINMAX);
731         }
732     }
733
734     switch (nCode)
735     {
736         case HCBT_CREATEWND:
737         {
738 #if 0 /* Uncomment this once the test succeeds in all cases */
739             static const RECT rc_null;
740             RECT rc;
741 #endif
742             LONG style;
743             CBT_CREATEWNDA *createwnd = (CBT_CREATEWNDA *)lParam;
744             trace("HCBT_CREATEWND: hwnd %p, parent %p, style %08lx\n",
745                   (HWND)wParam, createwnd->lpcs->hwndParent, createwnd->lpcs->style);
746             ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n");
747
748             /* WS_VISIBLE should be turned off yet */
749             style = createwnd->lpcs->style & ~WS_VISIBLE;
750             ok(style == GetWindowLongA((HWND)wParam, GWL_STYLE),
751                 "style of hwnd and style in the CREATESTRUCT do not match: %08lx != %08lx\n",
752                 GetWindowLongA((HWND)wParam, GWL_STYLE), style);
753
754 #if 0 /* Uncomment this once the test succeeds in all cases */
755             if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
756             {
757                 ok(GetParent((HWND)wParam) == hwndMessage,
758                    "wrong result from GetParent %p: message window %p\n",
759                    GetParent((HWND)wParam), hwndMessage);
760             }
761             else
762                 ok(!GetParent((HWND)wParam), "GetParent should return 0 at this point\n");
763
764             ok(!GetWindow((HWND)wParam, GW_OWNER), "GW_OWNER should be set to 0 at this point\n");
765 #endif
766 #if 0       /* while NT assigns GW_HWNDFIRST/LAST some values at this point,
767              * Win9x still has them set to 0.
768              */
769             ok(GetWindow((HWND)wParam, GW_HWNDFIRST) != 0, "GW_HWNDFIRST should not be set to 0 at this point\n");
770             ok(GetWindow((HWND)wParam, GW_HWNDLAST) != 0, "GW_HWNDLAST should not be set to 0 at this point\n");
771 #endif
772             ok(!GetWindow((HWND)wParam, GW_HWNDPREV), "GW_HWNDPREV should be set to 0 at this point\n");
773             ok(!GetWindow((HWND)wParam, GW_HWNDNEXT), "GW_HWNDNEXT should be set to 0 at this point\n");
774
775 #if 0 /* Uncomment this once the test succeeds in all cases */
776             if (pGetAncestor)
777             {
778                 ok(pGetAncestor((HWND)wParam, GA_PARENT) == hwndMessage, "GA_PARENT should be set to hwndMessage at this point\n");
779                 ok(pGetAncestor((HWND)wParam, GA_ROOT) == (HWND)wParam,
780                    "GA_ROOT is set to %p, expected %p\n", pGetAncestor((HWND)wParam, GA_ROOT), (HWND)wParam);
781
782                 if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
783                     ok(pGetAncestor((HWND)wParam, GA_ROOTOWNER) == hwndMessage,
784                        "GA_ROOTOWNER should be set to hwndMessage at this point\n");
785                 else
786                     ok(pGetAncestor((HWND)wParam, GA_ROOTOWNER) == (HWND)wParam,
787                        "GA_ROOTOWNER is set to %p, expected %p\n", pGetAncestor((HWND)wParam, GA_ROOTOWNER), (HWND)wParam);
788             }
789
790             ok(GetWindowRect((HWND)wParam, &rc), "GetWindowRect failed\n");
791             ok(EqualRect(&rc, &rc_null), "window rect should be set to 0 HCBT_CREATEWND\n");
792             ok(GetClientRect((HWND)wParam, &rc), "GetClientRect failed\n");
793             ok(EqualRect(&rc, &rc_null), "client rect should be set to 0 on HCBT_CREATEWND\n");
794 #endif
795             break;
796         }
797     }
798
799     return CallNextHookEx(hhook, nCode, wParam, lParam);
800 }
801
802 static void test_shell_window(void)
803 {
804     BOOL ret;
805     DWORD error;
806     HMODULE hinst, hUser32;
807     BOOL (WINAPI*SetShellWindow)(HWND);
808     BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
809     HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5;
810     HWND shellWindow, nextWnd;
811
812     if (!GetWindowLongW(GetDesktopWindow(), GWL_STYLE))
813     {
814         trace("Skipping shell window test on Win9x\n");
815         return;
816     }
817
818     shellWindow = GetShellWindow();
819     hinst = GetModuleHandle(0);
820     hUser32 = GetModuleHandleA("user32");
821
822     SetShellWindow = (void *)GetProcAddress(hUser32, "SetShellWindow");
823     SetShellWindowEx = (void *)GetProcAddress(hUser32, "SetShellWindowEx");
824
825     trace("previous shell window: %p\n", shellWindow);
826
827     if (shellWindow) {
828         DWORD pid;
829         HANDLE hProcess;
830
831         ret = DestroyWindow(shellWindow);
832         error = GetLastError();
833
834         ok(!ret, "DestroyWindow(shellWindow)\n");
835         /* passes on Win XP, but not on Win98 */
836         ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n");
837
838         /* close old shell instance */
839         GetWindowThreadProcessId(shellWindow, &pid);
840         hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
841         ret = TerminateProcess(hProcess, 0);
842         ok(ret, "termination of previous shell process failed: GetLastError()=%ld\n", GetLastError());
843         WaitForSingleObject(hProcess, INFINITE);    /* wait for termination */
844         CloseHandle(hProcess);
845     }
846
847     hwnd1 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0);
848     trace("created window 1: %p\n", hwnd1);
849
850     ret = SetShellWindow(hwnd1);
851     ok(ret, "first call to SetShellWindow(hwnd1)\n");
852     shellWindow = GetShellWindow();
853     ok(shellWindow==hwnd1, "wrong shell window: %p\n", shellWindow);
854
855     ret = SetShellWindow(hwnd1);
856     ok(!ret, "second call to SetShellWindow(hwnd1)\n");
857
858     ret = SetShellWindow(0);
859     error = GetLastError();
860     /* passes on Win XP, but not on Win98
861     ok(!ret, "reset shell window by SetShellWindow(0)\n");
862     ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */
863
864     ret = SetShellWindow(hwnd1);
865     /* passes on Win XP, but not on Win98
866     ok(!ret, "third call to SetShellWindow(hwnd1)\n"); */
867
868     todo_wine
869     {
870         SetWindowLong(hwnd1, GWL_EXSTYLE, GetWindowLong(hwnd1,GWL_EXSTYLE)|WS_EX_TOPMOST);
871         ret = GetWindowLong(hwnd1,GWL_EXSTYLE)&WS_EX_TOPMOST? TRUE: FALSE;
872         ok(!ret, "SetWindowExStyle(hwnd1, WS_EX_TOPMOST)\n");
873     }
874
875     ret = DestroyWindow(hwnd1);
876     ok(ret, "DestroyWindow(hwnd1)\n");
877
878     hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0);
879     trace("created window 2: %p\n", hwnd2);
880     ret = SetShellWindow(hwnd2);
881     ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST\n");
882
883     hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0);
884     trace("created window 3: %p\n", hwnd3);
885
886     hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0);
887     trace("created window 4: %p\n", hwnd4);
888
889     nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
890     ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd);
891
892     ret = SetShellWindow(hwnd4);
893     ok(ret, "SetShellWindow(hwnd4)\n");
894     shellWindow = GetShellWindow();
895     ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow);
896
897     nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
898     ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd);
899
900     ret = SetWindowPos(hwnd4, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
901     ok(ret, "SetWindowPos(hwnd4, HWND_TOPMOST)\n");
902
903     ret = SetWindowPos(hwnd4, hwnd3, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
904     ok(ret, "SetWindowPos(hwnd4, hwnd3\n");
905
906     ret = SetShellWindow(hwnd3);
907     ok(!ret, "SetShellWindow(hwnd3)\n");
908     shellWindow = GetShellWindow();
909     ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow);
910
911     hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0);
912     trace("created window 5: %p\n", hwnd5);
913     ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
914     ok(ret, "SetWindowPos(hwnd4, hwnd5)\n");
915
916     todo_wine
917     {
918         nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
919         ok(nextWnd==0, "wrong next window for hwnd4 after SetWindowPos(): %p - expected 0\n", nextWnd);
920     }
921
922     /* destroy test windows */
923     DestroyWindow(hwnd2);
924     DestroyWindow(hwnd3);
925     DestroyWindow(hwnd4);
926     DestroyWindow(hwnd5);
927 }
928
929 /************** MDI test ****************/
930
931 static const char mdi_lParam_test_message[] = "just a test string";
932
933 static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id)
934 {
935     MDICREATESTRUCTA mdi_cs;
936     HWND mdi_child;
937     static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0};
938     static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0};
939     BOOL isWin9x = FALSE;
940
941     mdi_cs.szClass = "MDI_child_Class_1";
942     mdi_cs.szTitle = "MDI child";
943     mdi_cs.hOwner = GetModuleHandle(0);
944     mdi_cs.x = CW_USEDEFAULT;
945     mdi_cs.y = CW_USEDEFAULT;
946     mdi_cs.cx = CW_USEDEFAULT;
947     mdi_cs.cy = CW_USEDEFAULT;
948     mdi_cs.style = 0;
949     mdi_cs.lParam = (LPARAM)mdi_lParam_test_message;
950     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
951     ok(mdi_child != 0, "MDI child creation failed\n");
952     ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
953     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
954     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
955
956     mdi_cs.style = 0x7fffffff; /* without WS_POPUP */
957     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
958     ok(mdi_child != 0, "MDI child creation failed\n");
959     ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
960     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
961     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
962
963     mdi_cs.style = 0xffffffff; /* with WS_POPUP */
964     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
965     if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
966     {
967         ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
968     }
969     else
970     {
971         ok(mdi_child != 0, "MDI child creation failed\n");
972         ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
973         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
974         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
975     }
976
977     /* test MDICREATESTRUCT A<->W mapping */
978     /* MDICREATESTRUCTA and MDICREATESTRUCTW have the same layout */
979     mdi_cs.style = 0;
980     mdi_cs.szClass = (LPCSTR)classW;
981     mdi_cs.szTitle = (LPCSTR)titleW;
982     SetLastError(0xdeadbeef);
983     mdi_child = (HWND)SendMessageW(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
984     if (!mdi_child)
985     {
986         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
987             isWin9x = TRUE;
988         else
989             ok(mdi_child != 0, "MDI child creation failed\n");
990     }
991     else
992     {
993         ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
994         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
995         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
996     }
997
998     mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
999                                  0,
1000                                  CW_USEDEFAULT, CW_USEDEFAULT,
1001                                  CW_USEDEFAULT, CW_USEDEFAULT,
1002                                  mdi_client, GetModuleHandle(0),
1003                                  (LPARAM)mdi_lParam_test_message);
1004     ok(mdi_child != 0, "MDI child creation failed\n");
1005     ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1006     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1007     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1008
1009     mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
1010                                  0x7fffffff, /* without WS_POPUP */
1011                                  CW_USEDEFAULT, CW_USEDEFAULT,
1012                                  CW_USEDEFAULT, CW_USEDEFAULT,
1013                                  mdi_client, GetModuleHandle(0),
1014                                  (LPARAM)mdi_lParam_test_message);
1015     ok(mdi_child != 0, "MDI child creation failed\n");
1016     ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1017     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1018     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1019
1020     mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
1021                                  0xffffffff, /* with WS_POPUP */
1022                                  CW_USEDEFAULT, CW_USEDEFAULT,
1023                                  CW_USEDEFAULT, CW_USEDEFAULT,
1024                                  mdi_client, GetModuleHandle(0),
1025                                  (LPARAM)mdi_lParam_test_message);
1026     if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1027     {
1028         ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
1029     }
1030     else
1031     {
1032         ok(mdi_child != 0, "MDI child creation failed\n");
1033         ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1034         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1035         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1036     }
1037
1038     /* test MDICREATESTRUCT A<->W mapping */
1039     SetLastError(0xdeadbeef);
1040     mdi_child = CreateMDIWindowW(classW, titleW,
1041                                  0,
1042                                  CW_USEDEFAULT, CW_USEDEFAULT,
1043                                  CW_USEDEFAULT, CW_USEDEFAULT,
1044                                  mdi_client, GetModuleHandle(0),
1045                                  (LPARAM)mdi_lParam_test_message);
1046     if (!mdi_child)
1047     {
1048         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1049             isWin9x = TRUE;
1050         else
1051             ok(mdi_child != 0, "MDI child creation failed\n");
1052     }
1053     else
1054     {
1055         ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1056         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1057         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1058     }
1059
1060     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
1061                                 0,
1062                                 CW_USEDEFAULT, CW_USEDEFAULT,
1063                                 CW_USEDEFAULT, CW_USEDEFAULT,
1064                                 mdi_client, 0, GetModuleHandle(0),
1065                                 (LPVOID)mdi_lParam_test_message);
1066     ok(mdi_child != 0, "MDI child creation failed\n");
1067     ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1068     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1069     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1070
1071     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
1072                                 0x7fffffff, /* without WS_POPUP */
1073                                 CW_USEDEFAULT, CW_USEDEFAULT,
1074                                 CW_USEDEFAULT, CW_USEDEFAULT,
1075                                 mdi_client, 0, GetModuleHandle(0),
1076                                 (LPVOID)mdi_lParam_test_message);
1077     ok(mdi_child != 0, "MDI child creation failed\n");
1078     ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1079     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1080     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1081
1082     mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
1083                                 0xffffffff, /* with WS_POPUP */
1084                                 CW_USEDEFAULT, CW_USEDEFAULT,
1085                                 CW_USEDEFAULT, CW_USEDEFAULT,
1086                                 mdi_client, 0, GetModuleHandle(0),
1087                                 (LPVOID)mdi_lParam_test_message);
1088     if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1089     {
1090         ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
1091     }
1092     else
1093     {
1094         ok(mdi_child != 0, "MDI child creation failed\n");
1095         ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1096         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1097         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1098     }
1099
1100     /* test MDICREATESTRUCT A<->W mapping */
1101     SetLastError(0xdeadbeef);
1102     mdi_child = CreateWindowExW(WS_EX_MDICHILD, classW, titleW,
1103                                 0,
1104                                 CW_USEDEFAULT, CW_USEDEFAULT,
1105                                 CW_USEDEFAULT, CW_USEDEFAULT,
1106                                 mdi_client, 0, GetModuleHandle(0),
1107                                 (LPVOID)mdi_lParam_test_message);
1108     if (!mdi_child)
1109     {
1110         if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1111             isWin9x = TRUE;
1112         else
1113             ok(mdi_child != 0, "MDI child creation failed\n");
1114     }
1115     else
1116     {
1117         ok(GetWindowLongA(mdi_child, GWL_ID) == first_id, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1118         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1119         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1120     }
1121
1122     /* This test fails on Win9x */
1123     if (!isWin9x)
1124     {
1125         mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child",
1126                                 WS_CHILD,
1127                                 CW_USEDEFAULT, CW_USEDEFAULT,
1128                                 CW_USEDEFAULT, CW_USEDEFAULT,
1129                                 parent, 0, GetModuleHandle(0),
1130                                 (LPVOID)mdi_lParam_test_message);
1131         ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n");
1132     }
1133
1134     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1135                                 WS_CHILD, /* without WS_POPUP */
1136                                 CW_USEDEFAULT, CW_USEDEFAULT,
1137                                 CW_USEDEFAULT, CW_USEDEFAULT,
1138                                 mdi_client, 0, GetModuleHandle(0),
1139                                 (LPVOID)mdi_lParam_test_message);
1140     ok(mdi_child != 0, "MDI child creation failed\n");
1141     ok(GetWindowLongA(mdi_child, GWL_ID) == 0, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1142     DestroyWindow(mdi_child);
1143
1144     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1145                                 WS_CHILD | WS_POPUP, /* with WS_POPUP */
1146                                 CW_USEDEFAULT, CW_USEDEFAULT,
1147                                 CW_USEDEFAULT, CW_USEDEFAULT,
1148                                 mdi_client, 0, GetModuleHandle(0),
1149                                 (LPVOID)mdi_lParam_test_message);
1150     ok(mdi_child != 0, "MDI child creation failed\n");
1151     ok(GetWindowLongA(mdi_child, GWL_ID) == 0, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1152     DestroyWindow(mdi_child);
1153
1154     /* maximized child */
1155     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1156                                 WS_CHILD | WS_MAXIMIZE,
1157                                 CW_USEDEFAULT, CW_USEDEFAULT,
1158                                 CW_USEDEFAULT, CW_USEDEFAULT,
1159                                 mdi_client, 0, GetModuleHandle(0),
1160                                 (LPVOID)mdi_lParam_test_message);
1161     ok(mdi_child != 0, "MDI child creation failed\n");
1162     ok(GetWindowLongA(mdi_child, GWL_ID) == 0, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1163     DestroyWindow(mdi_child);
1164
1165     trace("Creating maximized child with a caption\n");
1166     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1167                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION,
1168                                 CW_USEDEFAULT, CW_USEDEFAULT,
1169                                 CW_USEDEFAULT, CW_USEDEFAULT,
1170                                 mdi_client, 0, GetModuleHandle(0),
1171                                 (LPVOID)mdi_lParam_test_message);
1172     ok(mdi_child != 0, "MDI child creation failed\n");
1173     ok(GetWindowLongA(mdi_child, GWL_ID) == 0, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1174     DestroyWindow(mdi_child);
1175
1176     trace("Creating maximized child with a caption and a thick frame\n");
1177     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1178                                 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
1179                                 CW_USEDEFAULT, CW_USEDEFAULT,
1180                                 CW_USEDEFAULT, CW_USEDEFAULT,
1181                                 mdi_client, 0, GetModuleHandle(0),
1182                                 (LPVOID)mdi_lParam_test_message);
1183     ok(mdi_child != 0, "MDI child creation failed\n");
1184     ok(GetWindowLongA(mdi_child, GWL_ID) == 0, "wrong child id %ld\n", GetWindowLongA(mdi_child, GWL_ID));
1185     DestroyWindow(mdi_child);
1186 }
1187
1188 /**********************************************************************
1189  * MDI_ChildGetMinMaxInfo (copied from windows/mdi.c)
1190  *
1191  * Note: The rule here is that client rect of the maximized MDI child
1192  *       is equal to the client rect of the MDI client window.
1193  */
1194 static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax )
1195 {
1196     RECT rect;
1197
1198     GetClientRect( client, &rect );
1199     AdjustWindowRectEx( &rect, GetWindowLongA( hwnd, GWL_STYLE ),
1200                         0, GetWindowLongA( hwnd, GWL_EXSTYLE ));
1201
1202     rect.right -= rect.left;
1203     rect.bottom -= rect.top;
1204     lpMinMax->ptMaxSize.x = rect.right;
1205     lpMinMax->ptMaxSize.y = rect.bottom;
1206
1207     lpMinMax->ptMaxPosition.x = rect.left;
1208     lpMinMax->ptMaxPosition.y = rect.top;
1209
1210     trace("max rect (%ld,%ld - %ld, %ld)\n",
1211            rect.left, rect.top, rect.right, rect.bottom);
1212 }
1213
1214 static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1215 {
1216     switch (msg)
1217     {
1218         case WM_NCCREATE:
1219         case WM_CREATE:
1220         {
1221             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
1222             MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams;
1223
1224             ok(cs->dwExStyle & WS_EX_MDICHILD, "WS_EX_MDICHILD should be set\n");
1225             ok(mdi_cs->lParam == (LPARAM)mdi_lParam_test_message, "wrong mdi_cs->lParam\n");
1226
1227             ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_1"), "wrong class name\n");
1228             ok(!lstrcmpA(cs->lpszClass, mdi_cs->szClass), "class name does not match\n");
1229             ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
1230             ok(!lstrcmpA(cs->lpszName, mdi_cs->szTitle), "title does not match\n");
1231             ok(cs->hInstance == mdi_cs->hOwner, "%p != %p\n", cs->hInstance, mdi_cs->hOwner);
1232
1233             /* MDICREATESTRUCT should have original values */
1234             ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff,
1235                 "mdi_cs->style does not match (%08lx)\n", mdi_cs->style);
1236             ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x);
1237             ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y);
1238             ok(mdi_cs->cx == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cx);
1239             ok(mdi_cs->cy == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cy);
1240
1241             /* CREATESTRUCT should have fixed values */
1242             ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);
1243             ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
1244
1245             /* cx/cy == CW_USEDEFAULT are translated to NOT zero values */
1246             ok(cs->cx != CW_USEDEFAULT && cs->cx != 0, "%d == CW_USEDEFAULT\n", cs->cx);
1247             ok(cs->cy != CW_USEDEFAULT && cs->cy != 0, "%d == CW_USEDEFAULT\n", cs->cy);
1248
1249             ok(!(cs->style & WS_POPUP), "WS_POPUP is not allowed\n");
1250
1251             if (GetWindowLongA(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1252             {
1253                 LONG style = mdi_cs->style | WS_CHILD | WS_CLIPSIBLINGS;
1254                 ok(cs->style == style,
1255                    "cs->style does not match (%08lx)\n", cs->style);
1256             }
1257             else
1258             {
1259                 LONG style = mdi_cs->style;
1260                 style &= ~WS_POPUP;
1261                 style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1262                     WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1263                 ok(cs->style == style,
1264                    "cs->style does not match (%08lx)\n", cs->style);
1265             }
1266             break;
1267         }
1268
1269         case WM_GETMINMAXINFO:
1270         {
1271             HWND client = GetParent(hwnd);
1272             RECT rc;
1273             MINMAXINFO *minmax = (MINMAXINFO *)lparam;
1274             MINMAXINFO my_minmax;
1275             LONG style, exstyle;
1276
1277             style = GetWindowLongA(hwnd, GWL_STYLE);
1278             exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1279
1280             GetWindowRect(client, &rc);
1281             trace("MDI client %p window size = (%ld x %ld)\n", client, rc.right-rc.left, rc.bottom-rc.top);
1282             GetClientRect(client, &rc);
1283             trace("MDI client %p client size = (%ld x %ld)\n", client, rc.right, rc.bottom);
1284             trace("screen size: %d x %d\n", GetSystemMetrics(SM_CXSCREEN),
1285                                             GetSystemMetrics(SM_CYSCREEN));
1286
1287             GetClientRect(client, &rc);
1288             if ((style & WS_CAPTION) == WS_CAPTION)
1289                 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
1290             AdjustWindowRectEx(&rc, style, 0, exstyle);
1291             trace("MDI child: calculated max window size = (%ld x %ld)\n", rc.right-rc.left, rc.bottom-rc.top);
1292
1293             trace("ptReserved = (%ld,%ld)\n"
1294                   "ptMaxSize = (%ld,%ld)\n"
1295                   "ptMaxPosition = (%ld,%ld)\n"
1296                   "ptMinTrackSize = (%ld,%ld)\n"
1297                   "ptMaxTrackSize = (%ld,%ld)\n",
1298                   minmax->ptReserved.x, minmax->ptReserved.y,
1299                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
1300                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
1301                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
1302                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
1303
1304             ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %ld != %ld\n",
1305                minmax->ptMaxSize.x, rc.right - rc.left);
1306             ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %ld != %ld\n",
1307                minmax->ptMaxSize.y, rc.bottom - rc.top);
1308
1309             DefMDIChildProcA(hwnd, msg, wparam, lparam);
1310
1311             trace("DefMDIChildProc returned:\n"
1312                   "ptReserved = (%ld,%ld)\n"
1313                   "ptMaxSize = (%ld,%ld)\n"
1314                   "ptMaxPosition = (%ld,%ld)\n"
1315                   "ptMinTrackSize = (%ld,%ld)\n"
1316                   "ptMaxTrackSize = (%ld,%ld)\n",
1317                   minmax->ptReserved.x, minmax->ptReserved.y,
1318                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
1319                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
1320                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
1321                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
1322
1323             MDI_ChildGetMinMaxInfo(client, hwnd, &my_minmax);
1324             ok(minmax->ptMaxSize.x == my_minmax.ptMaxSize.x, "default width of maximized child %ld != %ld\n",
1325                minmax->ptMaxSize.x, my_minmax.ptMaxSize.x);
1326             ok(minmax->ptMaxSize.y == my_minmax.ptMaxSize.y, "default height of maximized child %ld != %ld\n",
1327                minmax->ptMaxSize.y, my_minmax.ptMaxSize.y);
1328
1329             return 1;
1330         }
1331
1332         case WM_MDIACTIVATE:
1333         {
1334             HWND active, client = GetParent(hwnd);
1335             /*trace("%p WM_MDIACTIVATE %08x %08lx\n", hwnd, wparam, lparam);*/
1336             active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
1337             if (hwnd == (HWND)lparam) /* if we are being activated */
1338                 ok (active == (HWND)lparam, "new active %p != active %p\n", (HWND)lparam, active);
1339             else
1340                 ok (active == (HWND)wparam, "old active %p != active %p\n", (HWND)wparam, active);
1341             break;
1342         }
1343     }
1344     return DefMDIChildProcA(hwnd, msg, wparam, lparam);
1345 }
1346
1347 static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1348 {
1349     switch (msg)
1350     {
1351         case WM_NCCREATE:
1352         case WM_CREATE:
1353         {
1354             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
1355
1356             trace("%s\n", (msg == WM_NCCREATE) ? "WM_NCCREATE" : "WM_CREATE");
1357             trace("x %d, y %d, cx %d, cy %d\n", cs->x, cs->y, cs->cx, cs->cy);
1358
1359             ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n");
1360             ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n");
1361
1362             ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_2"), "wrong class name\n");
1363             ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
1364
1365             /* CREATESTRUCT should have fixed values */
1366             /* For some reason Win9x doesn't translate cs->x from CW_USEDEFAULT,
1367                while NT does. */
1368             /*ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);*/
1369             ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
1370
1371             /* cx/cy == CW_USEDEFAULT are translated to 0 */
1372             /* For some reason Win98 doesn't translate cs->cx from CW_USEDEFAULT,
1373                while Win95, Win2k, WinXP do. */
1374             /*ok(cs->cx == 0, "%d != 0\n", cs->cx);*/
1375             ok(cs->cy == 0, "%d != 0\n", cs->cy);
1376             break;
1377         }
1378
1379         case WM_GETMINMAXINFO:
1380         {
1381             HWND parent = GetParent(hwnd);
1382             RECT rc;
1383             MINMAXINFO *minmax = (MINMAXINFO *)lparam;
1384             LONG style, exstyle;
1385
1386             trace("WM_GETMINMAXINFO\n");
1387
1388             style = GetWindowLongA(hwnd, GWL_STYLE);
1389             exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1390
1391             GetClientRect(parent, &rc);
1392             trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
1393
1394             GetClientRect(parent, &rc);
1395             if ((style & WS_CAPTION) == WS_CAPTION)
1396                 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
1397             AdjustWindowRectEx(&rc, style, 0, exstyle);
1398             trace("calculated max child window size = (%ld x %ld)\n", rc.right-rc.left, rc.bottom-rc.top);
1399
1400             trace("ptReserved = (%ld,%ld)\n"
1401                   "ptMaxSize = (%ld,%ld)\n"
1402                   "ptMaxPosition = (%ld,%ld)\n"
1403                   "ptMinTrackSize = (%ld,%ld)\n"
1404                   "ptMaxTrackSize = (%ld,%ld)\n",
1405                   minmax->ptReserved.x, minmax->ptReserved.y,
1406                   minmax->ptMaxSize.x, minmax->ptMaxSize.y,
1407                   minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
1408                   minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
1409                   minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
1410
1411             ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %ld != %ld\n",
1412                minmax->ptMaxSize.x, rc.right - rc.left);
1413             ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %ld != %ld\n",
1414                minmax->ptMaxSize.y, rc.bottom - rc.top);
1415             break;
1416         }
1417
1418         case WM_WINDOWPOSCHANGED:
1419         {
1420             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1421             RECT rc1, rc2;
1422
1423             GetWindowRect(hwnd, &rc1);
1424             trace("window: (%ld,%ld)-(%ld,%ld)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
1425             SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
1426             /* note: winpos coordinates are relative to parent */
1427             MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
1428             trace("pos: (%ld,%ld)-(%ld,%ld)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
1429             ok(EqualRect(&rc1, &rc2), "rects do not match\n");
1430
1431             GetWindowRect(hwnd, &rc1);
1432             GetClientRect(hwnd, &rc2);
1433             DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
1434             MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
1435             ok(EqualRect(&rc1, &rc2), "rects do not match\n");
1436         }
1437         /* fall through */
1438         case WM_WINDOWPOSCHANGING:
1439         {
1440             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1441             WINDOWPOS my_winpos = *winpos;
1442
1443             trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1444             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1445                   winpos->hwnd, winpos->hwndInsertAfter,
1446                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1447
1448             DefWindowProcA(hwnd, msg, wparam, lparam);
1449
1450             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1451                   winpos->hwnd, winpos->hwndInsertAfter,
1452                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1453
1454             ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)),
1455                "DefWindowProc should not change WINDOWPOS values\n");
1456
1457             return 1;
1458         }
1459     }
1460     return DefWindowProcA(hwnd, msg, wparam, lparam);
1461 }
1462
1463 static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1464 {
1465     static HWND mdi_client;
1466
1467     switch (msg)
1468     {
1469         case WM_CREATE:
1470         {
1471             CLIENTCREATESTRUCT client_cs;
1472             RECT rc;
1473
1474             GetClientRect(hwnd, &rc);
1475
1476             client_cs.hWindowMenu = 0;
1477             client_cs.idFirstChild = 1;
1478
1479             /* MDIClient without MDIS_ALLCHILDSTYLES */
1480             mdi_client = CreateWindowExA(0, "mdiclient",
1481                                          NULL,
1482                                          WS_CHILD /*| WS_VISIBLE*/,
1483                                           /* tests depend on a not zero MDIClient size */
1484                                          0, 0, rc.right, rc.bottom,
1485                                          hwnd, 0, GetModuleHandle(0),
1486                                          (LPVOID)&client_cs);
1487             assert(mdi_client);
1488             test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild);
1489             DestroyWindow(mdi_client);
1490
1491             /* MDIClient with MDIS_ALLCHILDSTYLES */
1492             mdi_client = CreateWindowExA(0, "mdiclient",
1493                                          NULL,
1494                                          WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/,
1495                                           /* tests depend on a not zero MDIClient size */
1496                                          0, 0, rc.right, rc.bottom,
1497                                          hwnd, 0, GetModuleHandle(0),
1498                                          (LPVOID)&client_cs);
1499             assert(mdi_client);
1500             test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild);
1501             DestroyWindow(mdi_client);
1502             break;
1503         }
1504
1505         case WM_WINDOWPOSCHANGED:
1506         {
1507             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1508             RECT rc1, rc2;
1509
1510             GetWindowRect(hwnd, &rc1);
1511             trace("window: (%ld,%ld)-(%ld,%ld)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
1512             SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
1513             /* note: winpos coordinates are relative to parent */
1514             MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
1515             trace("pos: (%ld,%ld)-(%ld,%ld)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
1516             ok(EqualRect(&rc1, &rc2), "rects do not match\n");
1517
1518             GetWindowRect(hwnd, &rc1);
1519             GetClientRect(hwnd, &rc2);
1520             DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
1521             MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
1522             ok(EqualRect(&rc1, &rc2), "rects do not match\n");
1523         }
1524         /* fall through */
1525         case WM_WINDOWPOSCHANGING:
1526         {
1527             WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1528             WINDOWPOS my_winpos = *winpos;
1529
1530             trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1531             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1532                   winpos->hwnd, winpos->hwndInsertAfter,
1533                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1534
1535             DefWindowProcA(hwnd, msg, wparam, lparam);
1536
1537             trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1538                   winpos->hwnd, winpos->hwndInsertAfter,
1539                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1540
1541             ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)),
1542                "DefWindowProc should not change WINDOWPOS values\n");
1543
1544             return 1;
1545         }
1546
1547         case WM_CLOSE:
1548             PostQuitMessage(0);
1549             break;
1550     }
1551     return DefFrameProcA(hwnd, mdi_client, msg, wparam, lparam);
1552 }
1553
1554 static BOOL mdi_RegisterWindowClasses(void)
1555 {
1556     WNDCLASSA cls;
1557
1558     cls.style = 0;
1559     cls.lpfnWndProc = mdi_main_wnd_procA;
1560     cls.cbClsExtra = 0;
1561     cls.cbWndExtra = 0;
1562     cls.hInstance = GetModuleHandleA(0);
1563     cls.hIcon = 0;
1564     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1565     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1566     cls.lpszMenuName = NULL;
1567     cls.lpszClassName = "MDI_parent_Class";
1568     if(!RegisterClassA(&cls)) return FALSE;
1569
1570     cls.lpfnWndProc = mdi_child_wnd_proc_1;
1571     cls.lpszClassName = "MDI_child_Class_1";
1572     if(!RegisterClassA(&cls)) return FALSE;
1573
1574     cls.lpfnWndProc = mdi_child_wnd_proc_2;
1575     cls.lpszClassName = "MDI_child_Class_2";
1576     if(!RegisterClassA(&cls)) return FALSE;
1577
1578     return TRUE;
1579 }
1580
1581 static void test_mdi(void)
1582 {
1583     HWND mdi_hwndMain;
1584     /*MSG msg;*/
1585
1586     if (!mdi_RegisterWindowClasses()) assert(0);
1587
1588     mdi_hwndMain = CreateWindowExA(0, "MDI_parent_Class", "MDI parent window",
1589                                    WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1590                                    WS_MAXIMIZEBOX /*| WS_VISIBLE*/,
1591                                    100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1592                                    GetDesktopWindow(), 0,
1593                                    GetModuleHandle(0), NULL);
1594     assert(mdi_hwndMain);
1595 /*
1596     while(GetMessage(&msg, 0, 0, 0))
1597     {
1598         TranslateMessage(&msg);
1599         DispatchMessage(&msg);
1600     }
1601 */
1602 }
1603
1604 static void test_icons(void)
1605 {
1606     WNDCLASSEXA cls;
1607     HWND hwnd;
1608     HICON icon = LoadIconA(0, (LPSTR)IDI_APPLICATION);
1609     HICON icon2 = LoadIconA(0, (LPSTR)IDI_QUESTION);
1610     HICON small_icon = LoadImageA(0, (LPSTR)IDI_APPLICATION, IMAGE_ICON,
1611                                   GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED );
1612     HICON res;
1613
1614     cls.cbSize = sizeof(cls);
1615     cls.style = 0;
1616     cls.lpfnWndProc = DefWindowProcA;
1617     cls.cbClsExtra = 0;
1618     cls.cbWndExtra = 0;
1619     cls.hInstance = 0;
1620     cls.hIcon = LoadIconA(0, (LPSTR)IDI_HAND);
1621     cls.hIconSm = small_icon;
1622     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
1623     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1624     cls.lpszMenuName = NULL;
1625     cls.lpszClassName = "IconWindowClass";
1626
1627     RegisterClassExA(&cls);
1628
1629     hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0,
1630                            100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL);
1631     assert( hwnd );
1632
1633     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1634     ok( res == 0, "wrong big icon %p/0\n", res );
1635     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon );
1636     ok( res == 0, "wrong previous big icon %p/0\n", res );
1637     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1638     ok( res == icon, "wrong big icon after set %p/%p\n", res, icon );
1639     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 );
1640     ok( res == icon, "wrong previous big icon %p/%p\n", res, icon );
1641     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1642     ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 );
1643
1644     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
1645     ok( res == 0, "wrong small icon %p/0\n", res );
1646     /* this test is XP specific */
1647     /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
1648     ok( res != 0, "wrong small icon %p\n", res );*/
1649     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon );
1650     ok( res == 0, "wrong previous small icon %p/0\n", res );
1651     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
1652     ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );
1653     /* this test is XP specific */
1654     /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
1655     ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );*/
1656     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon );
1657     ok( res == icon, "wrong previous small icon %p/%p\n", res, icon );
1658     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
1659     ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );
1660     /* this test is XP specific */
1661     /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
1662     ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );*/
1663
1664     /* make sure the big icon hasn't changed */
1665     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
1666     ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 );
1667 }
1668
1669 static LRESULT WINAPI nccalcsize_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1670 {
1671     if (msg == WM_NCCALCSIZE)
1672     {
1673         RECT *rect = (RECT *)lparam;
1674         /* first time around increase the rectangle, next time decrease it */
1675         if (rect->left == 100) InflateRect( rect, 10, 10 );
1676         else InflateRect( rect, -10, -10 );
1677         return 0;
1678     }
1679     return DefWindowProc( hwnd, msg, wparam, lparam );
1680 }
1681
1682 static void test_SetWindowPos(HWND hwnd)
1683 {
1684     RECT orig_win_rc, rect;
1685     LONG_PTR old_proc;
1686     BOOL is_win9x = GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == 0;
1687
1688     SetRect(&rect, 111, 222, 333, 444);
1689     ok(!GetWindowRect(0, &rect), "GetWindowRect succeeded\n");
1690     ok(rect.left == 111 && rect.top == 222 && rect.right == 333 && rect.bottom == 444,
1691        "wrong window rect %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
1692
1693     SetRect(&rect, 111, 222, 333, 444);
1694     ok(!GetClientRect(0, &rect), "GetClientRect succeeded\n");
1695     ok(rect.left == 111 && rect.top == 222 && rect.right == 333 && rect.bottom == 444,
1696        "wrong window rect %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
1697
1698     GetWindowRect(hwnd, &orig_win_rc);
1699
1700     old_proc = SetWindowLongPtr( hwnd, GWLP_WNDPROC, (ULONG_PTR)nccalcsize_proc );
1701     SetWindowPos(hwnd, 0, 100, 100, 0, 0, SWP_NOZORDER|SWP_FRAMECHANGED);
1702     GetWindowRect( hwnd, &rect );
1703     ok( rect.left == 100 && rect.top == 100 && rect.right == 100 && rect.bottom == 100,
1704         "invalid window rect %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
1705     GetClientRect( hwnd, &rect );
1706     MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 );
1707     ok( rect.left == 90 && rect.top == 90 && rect.right == 110 && rect.bottom == 110,
1708         "invalid client rect %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
1709
1710     SetWindowPos(hwnd, 0, 200, 200, 0, 0, SWP_NOZORDER|SWP_FRAMECHANGED);
1711     GetWindowRect( hwnd, &rect );
1712     ok( rect.left == 200 && rect.top == 200 && rect.right == 200 && rect.bottom == 200,
1713         "invalid window rect %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
1714     GetClientRect( hwnd, &rect );
1715     MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 );
1716     ok( rect.left == 210 && rect.top == 210 && rect.right == 190 && rect.bottom == 190,
1717         "invalid client rect %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
1718
1719     SetWindowPos(hwnd, 0, orig_win_rc.left, orig_win_rc.top,
1720                  orig_win_rc.right, orig_win_rc.bottom, 0);
1721     SetWindowLongPtr( hwnd, GWLP_WNDPROC, old_proc );
1722
1723     /* Win9x truncates coordinates to 16-bit irrespectively */
1724     if (!is_win9x)
1725     {
1726         SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOMOVE);
1727         SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOMOVE);
1728
1729         SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOSIZE);
1730         SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOSIZE);
1731     }
1732
1733     SetWindowPos(hwnd, 0, orig_win_rc.left, orig_win_rc.top,
1734                  orig_win_rc.right, orig_win_rc.bottom, 0);
1735 }
1736
1737 static void test_SetMenu(HWND parent)
1738 {
1739     HWND child;
1740     HMENU hMenu, ret;
1741     BOOL is_win9x = GetWindowLongPtrW(parent, GWLP_WNDPROC) == 0;
1742     BOOL retok;
1743
1744     hMenu = CreateMenu();
1745     assert(hMenu);
1746
1747     ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
1748     test_nonclient_area(parent);
1749     ret = GetMenu(parent);
1750     ok(ret == hMenu, "unexpected menu id %p\n", ret);
1751     /* test whether we can destroy a menu assigned to a window */
1752     retok = DestroyMenu(hMenu);
1753     ok( retok, "DestroyMenu error %ld\n", GetLastError());
1754     ok(!IsMenu(hMenu), "menu handle should be not valid after DestroyMenu\n");
1755     ret = GetMenu(parent);
1756     /* This test fails on Win9x */
1757     if (!is_win9x)
1758         ok(ret == hMenu, "unexpected menu id %p\n", ret);
1759     ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
1760     test_nonclient_area(parent);
1761
1762     hMenu = CreateMenu();
1763     assert(hMenu);
1764
1765     /* parent */
1766     ret = GetMenu(parent);
1767     ok(ret == 0, "unexpected menu id %p\n", ret);
1768
1769     ok(!SetMenu(parent, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
1770     test_nonclient_area(parent);
1771     ret = GetMenu(parent);
1772     ok(ret == 0, "unexpected menu id %p\n", ret);
1773
1774     ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
1775     test_nonclient_area(parent);
1776     ret = GetMenu(parent);
1777     ok(ret == hMenu, "unexpected menu id %p\n", ret);
1778
1779     ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
1780     test_nonclient_area(parent);
1781     ret = GetMenu(parent);
1782     ok(ret == 0, "unexpected menu id %p\n", ret);
1783  
1784     /* child */
1785     child = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, parent, (HMENU)10, 0, NULL);
1786     assert(child);
1787
1788     ret = GetMenu(child);
1789     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1790
1791     ok(!SetMenu(child, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
1792     test_nonclient_area(child);
1793     ret = GetMenu(child);
1794     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1795
1796     ok(!SetMenu(child, hMenu), "SetMenu on a child window should fail\n");
1797     test_nonclient_area(child);
1798     ret = GetMenu(child);
1799     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1800
1801     ok(!SetMenu(child, 0), "SetMenu(0) on a child window should fail\n");
1802     test_nonclient_area(child);
1803     ret = GetMenu(child);
1804     ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
1805
1806     DestroyWindow(child);
1807     DestroyMenu(hMenu);
1808 }
1809
1810 static void test_window_tree(HWND parent, const DWORD *style, const int *order, int total)
1811 {
1812     HWND child[5], hwnd;
1813     int i;
1814
1815     assert(total <= 5);
1816
1817     hwnd = GetWindow(parent, GW_CHILD);
1818     ok(!hwnd, "have to start without children to perform the test\n");
1819
1820     for (i = 0; i < total; i++)
1821     {
1822         child[i] = CreateWindowExA(0, "static", "", style[i], 0,0,10,10,
1823                                    parent, 0, 0, NULL);
1824         trace("child[%d] = %p\n", i, child[i]);
1825         ok(child[i] != 0, "CreateWindowEx failed to create child window\n");
1826     }
1827
1828     hwnd = GetWindow(parent, GW_CHILD);
1829     ok(hwnd != 0, "GetWindow(GW_CHILD) failed\n");
1830     ok(hwnd == GetWindow(child[total - 1], GW_HWNDFIRST), "GW_HWNDFIRST is wrong\n");
1831     ok(child[order[total - 1]] == GetWindow(child[0], GW_HWNDLAST), "GW_HWNDLAST is wrong\n");
1832
1833     for (i = 0; i < total; i++)
1834     {
1835         trace("hwnd[%d] = %p\n", i, hwnd);
1836         ok(child[order[i]] == hwnd, "Z order of child #%d is wrong\n", i);
1837
1838         hwnd = GetWindow(hwnd, GW_HWNDNEXT);
1839     }
1840
1841     for (i = 0; i < total; i++)
1842         ok(DestroyWindow(child[i]), "DestroyWindow failed\n");
1843 }
1844
1845 static void test_children_zorder(HWND parent)
1846 {
1847     const DWORD simple_style[5] = { WS_CHILD, WS_CHILD, WS_CHILD, WS_CHILD,
1848                                     WS_CHILD };
1849     const int simple_order[5] = { 0, 1, 2, 3, 4 };
1850
1851     const DWORD complex_style[5] = { WS_CHILD, WS_CHILD | WS_MAXIMIZE,
1852                              WS_CHILD | WS_VISIBLE, WS_CHILD,
1853                              WS_CHILD | WS_MAXIMIZE | WS_VISIBLE };
1854     const int complex_order_1[1] = { 0 };
1855     const int complex_order_2[2] = { 1, 0 };
1856     const int complex_order_3[3] = { 1, 0, 2 };
1857     const int complex_order_4[4] = { 1, 0, 2, 3 };
1858     const int complex_order_5[5] = { 4, 1, 0, 2, 3 };
1859
1860     /* simple WS_CHILD */
1861     test_window_tree(parent, simple_style, simple_order, 5);
1862
1863     /* complex children styles */
1864     test_window_tree(parent, complex_style, complex_order_1, 1);
1865     test_window_tree(parent, complex_style, complex_order_2, 2);
1866     test_window_tree(parent, complex_style, complex_order_3, 3);
1867     test_window_tree(parent, complex_style, complex_order_4, 4);
1868     test_window_tree(parent, complex_style, complex_order_5, 5);
1869 }
1870
1871 static void test_SetFocus(HWND hwnd)
1872 {
1873     HWND child;
1874
1875     /* check if we can set focus to non-visible windows */
1876
1877     ShowWindow(hwnd, SW_SHOW);
1878     SetFocus(0);
1879     SetFocus(hwnd);
1880     ok( GetFocus() == hwnd, "Failed to set focus to visible window %p\n", hwnd );
1881     ok( GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE, "Window %p not visible\n", hwnd );
1882     ShowWindow(hwnd, SW_HIDE);
1883     SetFocus(0);
1884     SetFocus(hwnd);
1885     ok( GetFocus() == hwnd, "Failed to set focus to invisible window %p\n", hwnd );
1886     ok( !(GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE), "Window %p still visible\n", hwnd );
1887     child = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, hwnd, 0, 0, NULL);
1888     assert(child);
1889     SetFocus(child);
1890     ok( GetFocus() == child, "Failed to set focus to invisible child %p\n", child );
1891     ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
1892     ShowWindow(child, SW_SHOW);
1893     ok( GetWindowLong(child,GWL_STYLE) & WS_VISIBLE, "Child %p is not visible\n", child );
1894     ok( GetFocus() == child, "Focus no longer on child %p\n", child );
1895     ShowWindow(child, SW_HIDE);
1896     ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
1897     ok( GetFocus() == hwnd, "Focus should be on parent %p, not %p\n", hwnd, GetFocus() );
1898     ShowWindow(child, SW_SHOW);
1899     SetFocus(child);
1900     ok( GetFocus() == child, "Focus should be on child %p\n", child );
1901     SetWindowPos(child,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW);
1902     ok( GetFocus() == child, "Focus should still be on child %p\n", child );
1903
1904     ShowWindow(child, SW_HIDE);
1905     SetFocus(hwnd);
1906     ok( GetFocus() == hwnd, "Focus should be on parent %p, not %p\n", hwnd, GetFocus() );
1907     SetWindowPos(child,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
1908     ok( GetFocus() == hwnd, "Focus should still be on parent %p, not %p\n", hwnd, GetFocus() );
1909     ShowWindow(child, SW_HIDE);
1910     ok( GetFocus() == hwnd, "Focus should still be on parent %p, not %p\n", hwnd, GetFocus() );
1911
1912     ShowWindow(hwnd, SW_SHOW);
1913     ShowWindow(child, SW_SHOW);
1914     SetFocus(child);
1915     ok( GetFocus() == child, "Focus should be on child %p\n", child );
1916     EnableWindow(hwnd, FALSE);
1917     ok( GetFocus() == child, "Focus should still be on child %p\n", child );
1918     EnableWindow(hwnd, TRUE);
1919
1920     DestroyWindow( child );
1921 }
1922
1923 static void test_SetActiveWindow(HWND hwnd)
1924 {
1925     HWND hwnd2;
1926
1927     ShowWindow(hwnd, SW_SHOW);
1928     SetActiveWindow(0);
1929     SetActiveWindow(hwnd);
1930     ok( GetActiveWindow() == hwnd, "Failed to set focus to visible window %p\n", hwnd );
1931     SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW);
1932     ok( GetActiveWindow() == hwnd, "Window %p no longer active\n", hwnd );
1933     SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW);
1934     ShowWindow(hwnd, SW_HIDE);
1935     ok( GetActiveWindow() != hwnd, "Window %p is still active\n", hwnd );
1936
1937     /* trace("**testing an invisible window now\n"); */
1938     SetActiveWindow(hwnd);
1939     ok( GetActiveWindow() == hwnd, "Window %p not active\n", hwnd );
1940     ok( !(GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE), "Window %p is visible\n", hwnd );
1941     
1942     ShowWindow(hwnd, SW_SHOW);
1943
1944     hwnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, hwnd, 0, 0, NULL);
1945     ok( GetActiveWindow() == hwnd2, "Window %p is not active\n", hwnd2 );
1946     DestroyWindow(hwnd2);
1947     ok( GetActiveWindow() != hwnd2, "Window %p is still active\n", hwnd2 );
1948
1949     hwnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, hwnd, 0, 0, NULL);
1950     ok( GetActiveWindow() == hwnd2, "Window %p is not active\n", hwnd2 );
1951     SetWindowPos(hwnd2,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW);
1952     ok( GetActiveWindow() == hwnd2, "Window %p no longer active (%p)\n", hwnd2, GetActiveWindow() );
1953     DestroyWindow(hwnd2);
1954     ok( GetActiveWindow() != hwnd2, "Window %p is still active\n", hwnd2 );
1955 }
1956
1957 static void check_wnd_state(HWND active, HWND foreground, HWND focus, HWND capture)
1958 {
1959     ok(active == GetActiveWindow(), "GetActiveWindow() = %p\n", GetActiveWindow());
1960     if (foreground)
1961         ok(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow());
1962     ok(focus == GetFocus(), "GetFocus() = %p\n", GetFocus());
1963     ok(capture == GetCapture(), "GetCapture() = %p\n", GetCapture());
1964 }
1965
1966 static WNDPROC old_button_proc;
1967
1968 static LRESULT WINAPI button_hook_proc(HWND button, UINT msg, WPARAM wparam, LPARAM lparam)
1969 {
1970     LRESULT ret;
1971     USHORT key_state;
1972
1973     key_state = GetKeyState(VK_LBUTTON);
1974     ok(!(key_state & 0x8000), "VK_LBUTTON should not be pressed, state %04x\n", key_state);
1975
1976     ret = CallWindowProcA(old_button_proc, button, msg, wparam, lparam);
1977
1978     if (msg == WM_LBUTTONDOWN)
1979     {
1980         HWND hwnd, capture;
1981
1982         check_wnd_state(button, button, button, button);
1983
1984         hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
1985         assert(hwnd);
1986         trace("hwnd %p\n", hwnd);
1987
1988         check_wnd_state(button, button, button, button);
1989
1990         ShowWindow(hwnd, SW_SHOWNOACTIVATE);
1991
1992         check_wnd_state(button, button, button, button);
1993
1994         DestroyWindow(hwnd);
1995
1996         hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
1997         assert(hwnd);
1998         trace("hwnd %p\n", hwnd);
1999
2000         check_wnd_state(button, button, button, button);
2001
2002         /* button wnd proc should release capture on WM_KILLFOCUS if it does
2003          * match internal button state.
2004          */
2005         SendMessage(button, WM_KILLFOCUS, 0, 0);
2006         check_wnd_state(button, button, button, 0);
2007
2008         ShowWindow(hwnd, SW_SHOW);
2009         check_wnd_state(hwnd, hwnd, hwnd, 0);
2010
2011         capture = SetCapture(hwnd);
2012         ok(capture == 0, "SetCapture() = %p\n", capture);
2013
2014         check_wnd_state(hwnd, hwnd, hwnd, hwnd);
2015
2016         DestroyWindow(hwnd);
2017
2018         check_wnd_state(button, 0, button, 0);
2019     }
2020
2021     return ret;
2022 }
2023
2024 static void test_capture_1(void)
2025 {
2026     HWND button, capture;
2027
2028     capture = GetCapture();
2029     ok(capture == 0, "GetCapture() = %p\n", capture);
2030
2031     button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
2032     assert(button);
2033     trace("button %p\n", button);
2034
2035     old_button_proc = (WNDPROC)SetWindowLongPtrA(button, GWLP_WNDPROC, (LONG_PTR)button_hook_proc);
2036
2037     SendMessageA(button, WM_LBUTTONDOWN, 0, 0);
2038
2039     DestroyWindow(button);
2040 }
2041
2042 static void test_capture_2(void)
2043 {
2044     HWND button, hwnd, capture;
2045
2046     check_wnd_state(0, 0, 0, 0);
2047
2048     button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
2049     assert(button);
2050     trace("button %p\n", button);
2051
2052     check_wnd_state(button, button, button, 0);
2053
2054     capture = SetCapture(button);
2055     ok(capture == 0, "SetCapture() = %p\n", capture);
2056
2057     check_wnd_state(button, button, button, button);
2058
2059     /* button wnd proc should ignore WM_KILLFOCUS if it doesn't match
2060      * internal button state.
2061      */
2062     SendMessage(button, WM_KILLFOCUS, 0, 0);
2063     check_wnd_state(button, button, button, button);
2064
2065     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
2066     assert(hwnd);
2067     trace("hwnd %p\n", hwnd);
2068
2069     check_wnd_state(button, button, button, button);
2070
2071     ShowWindow(hwnd, SW_SHOWNOACTIVATE);
2072
2073     check_wnd_state(button, button, button, button);
2074
2075     DestroyWindow(hwnd);
2076
2077     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
2078     assert(hwnd);
2079     trace("hwnd %p\n", hwnd);
2080
2081     check_wnd_state(button, button, button, button);
2082
2083     ShowWindow(hwnd, SW_SHOW);
2084
2085     check_wnd_state(hwnd, hwnd, hwnd, button);
2086
2087     capture = SetCapture(hwnd);
2088     ok(capture == button, "SetCapture() = %p\n", capture);
2089
2090     check_wnd_state(hwnd, hwnd, hwnd, hwnd);
2091
2092     DestroyWindow(hwnd);
2093     check_wnd_state(button, button, button, 0);
2094
2095     DestroyWindow(button);
2096     check_wnd_state(0, 0, 0, 0);
2097 }
2098
2099 static void test_capture_3(HWND hwnd1, HWND hwnd2)
2100 {
2101     ShowWindow(hwnd1, SW_HIDE);
2102     ShowWindow(hwnd2, SW_HIDE);
2103
2104     ok(!IsWindowVisible(hwnd1), "%p should be invisible\n", hwnd1);
2105     ok(!IsWindowVisible(hwnd2), "%p should be invisible\n", hwnd2);
2106
2107     SetCapture(hwnd1);
2108     check_wnd_state(0, 0, 0, hwnd1);
2109
2110     SetCapture(hwnd2);
2111     check_wnd_state(0, 0, 0, hwnd2);
2112
2113     ShowWindow(hwnd1, SW_SHOW);
2114     check_wnd_state(hwnd1, hwnd1, hwnd1, hwnd2);
2115
2116     ReleaseCapture();
2117 }
2118
2119 static void test_keyboard_input(HWND hwnd)
2120 {
2121     MSG msg;
2122     BOOL ret;
2123
2124     ShowWindow(hwnd, SW_SHOW);
2125     UpdateWindow(hwnd);
2126
2127     ok(GetActiveWindow() == hwnd, "wrong active window %p\n", GetActiveWindow());
2128
2129     SetFocus(hwnd);
2130     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
2131
2132     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2133
2134     PostMessageA(hwnd, WM_KEYDOWN, 0, 0);
2135     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2136     ok(msg.hwnd == hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2137     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2138     ok( !ret, "message %04x available\n", msg.message);
2139
2140     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
2141
2142     PostThreadMessageA(GetCurrentThreadId(), WM_KEYDOWN, 0, 0);
2143     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2144     ok(!msg.hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2145     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2146     ok( !ret, "message %04x available\n", msg.message);
2147
2148     ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
2149
2150     keybd_event(VK_SPACE, 0, 0, 0);
2151     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2152     ok(msg.hwnd == hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2153     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2154     ok( !ret, "message %04x available\n", msg.message);
2155
2156     SetFocus(0);
2157     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2158
2159     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
2160
2161     PostMessageA(hwnd, WM_KEYDOWN, 0, 0);
2162     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2163     ok(msg.hwnd == hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2164     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2165     ok( !ret, "message %04x available\n", msg.message);
2166
2167     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2168
2169     PostThreadMessageA(GetCurrentThreadId(), WM_KEYDOWN, 0, 0);
2170     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2171     ok(!msg.hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2172     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2173     ok( !ret, "message %04x available\n", msg.message);
2174
2175     ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
2176
2177     keybd_event(VK_SPACE, 0, 0, 0);
2178     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2179     ok(msg.hwnd == hwnd && msg.message == WM_SYSKEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2180     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2181     ok( !ret, "message %04x available\n", msg.message);
2182 }
2183
2184 static void test_mouse_input(HWND hwnd)
2185 {
2186     RECT rc;
2187     POINT pt;
2188     int x, y;
2189     HWND popup;
2190     MSG msg;
2191     BOOL ret;
2192
2193     ShowWindow(hwnd, SW_SHOW);
2194     UpdateWindow(hwnd);
2195
2196     GetWindowRect(hwnd, &rc);
2197     trace("main window %p: (%ld,%ld)-(%ld,%ld)\n", hwnd, rc.left, rc.top, rc.right, rc.bottom);
2198
2199     popup = CreateWindowExA(0, "MainWindowClass", NULL, WS_POPUP,
2200                             rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
2201                             hwnd, 0, 0, NULL);
2202     assert(popup != 0);
2203     ShowWindow(popup, SW_SHOW);
2204     UpdateWindow(popup);
2205
2206     GetWindowRect(popup, &rc);
2207     trace("popup window %p: (%ld,%ld)-(%ld,%ld)\n", popup, rc.left, rc.top, rc.right, rc.bottom);
2208
2209     x = rc.left + (rc.right - rc.left) / 2;
2210     y = rc.top + (rc.bottom - rc.top) / 2;
2211     trace("setting cursor to (%d,%d)\n", x, y);
2212
2213     SetCursorPos(x, y);
2214     GetCursorPos(&pt);
2215     ok(x == pt.x && y == pt.y, "wrong cursor pos (%ld,%ld), expected (%d,%d)\n", pt.x, pt.y, x, y);
2216
2217     /* force the system to update its internal queue mouse position,
2218      * otherwise it won't generate relative mouse movements below.
2219      */
2220     mouse_event(MOUSEEVENTF_MOVE, -1, -1, 0, 0);
2221     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2222
2223     msg.message = 0;
2224     mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0);
2225     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2226     ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2227     /* FIXME: SetCursorPos in Wine generates additional WM_MOUSEMOVE message */
2228     if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
2229         ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2230     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2231     ok( !ret, "message %04x available\n", msg.message);
2232
2233     mouse_event(MOUSEEVENTF_MOVE, -1, -1, 0, 0);
2234     ShowWindow(popup, SW_HIDE);
2235     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
2236     ok(msg.hwnd == hwnd && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
2237     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2238
2239     mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0);
2240     ShowWindow(hwnd, SW_HIDE);
2241     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
2242     ok( !ret, "message %04x available\n", msg.message);
2243
2244     DestroyWindow(popup);
2245 }
2246
2247 static void test_validatergn(HWND hwnd)
2248 {
2249     HWND child;
2250     RECT rc, rc2;
2251     HRGN rgn;
2252     int ret;
2253     child = CreateWindowExA(0, "static", NULL, WS_CHILD| WS_VISIBLE, 10, 10, 10, 10, hwnd, 0, 0, NULL);
2254     ShowWindow(hwnd, SW_SHOW);
2255     UpdateWindow( hwnd);
2256     /* test that ValidateRect validates children*/
2257     InvalidateRect( child, NULL, 1);
2258     GetWindowRect( child, &rc);
2259     MapWindowPoints( NULL, hwnd, (POINT*) &rc, 2);
2260     ret = GetUpdateRect( child, &rc2, 0);
2261     ok( rc2.right > rc2.left && rc2.bottom > rc2.top,
2262             "Update rectangle is empty!\n");
2263     ValidateRect( hwnd, &rc);
2264     ret = GetUpdateRect( child, &rc2, 0);
2265     ok( rc2.left == 0 && rc2.top == 0 && rc2.right == 0 && rc2.bottom == 0,
2266             "Update rectangle %ld,%ld-%ld,%ld is not empty!\n", rc2.left, rc2.top,
2267             rc2.right, rc2.bottom);
2268
2269     /* now test ValidateRgn */
2270     InvalidateRect( child, NULL, 1);
2271     GetWindowRect( child, &rc);
2272     MapWindowPoints( NULL, hwnd, (POINT*) &rc, 2);
2273     rgn = CreateRectRgnIndirect( &rc);
2274     ValidateRgn( hwnd, rgn);
2275     ret = GetUpdateRect( child, &rc2, 0);
2276     ok( rc2.left == 0 && rc2.top == 0 && rc2.right == 0 && rc2.bottom == 0,
2277             "Update rectangle %ld,%ld-%ld,%ld is not empty!\n", rc2.left, rc2.top,
2278             rc2.right, rc2.bottom);
2279
2280     DeleteObject( rgn);
2281     DestroyWindow( child );
2282 }
2283
2284 static void nccalchelper(HWND hwnd, INT x, INT y, RECT *prc)
2285 {
2286     MoveWindow( hwnd, 0, 0, x, y, 0);
2287     GetWindowRect( hwnd, prc);
2288     trace("window rect is %ld,%ld - %ld,%ld\n", 
2289             prc->left,prc->top,prc->right,prc->bottom);
2290     DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)prc);
2291     trace("nccalc rect is %ld,%ld - %ld,%ld\n",
2292             prc->left,prc->top,prc->right,prc->bottom);
2293 }
2294
2295 static void test_nccalcscroll(HWND parent)
2296 {
2297     RECT rc1;
2298     INT sbheight = GetSystemMetrics( SM_CYHSCROLL);
2299     INT sbwidth = GetSystemMetrics( SM_CXVSCROLL);
2300     HWND hwnd = CreateWindowExA(0, "static", NULL, 
2301             WS_CHILD| WS_VISIBLE | WS_VSCROLL | WS_HSCROLL , 
2302             10, 10, 200, 200, parent, 0, 0, NULL); 
2303     ShowWindow( parent, SW_SHOW);
2304     UpdateWindow( parent);
2305
2306     /* test window too low for a horizontal scroll bar */
2307     nccalchelper( hwnd, 100, sbheight, &rc1);
2308     ok( rc1.bottom - rc1.top == sbheight, "Height should be %d size is %ld,%ld - %ld,%ld\n", 
2309             sbheight, rc1.left, rc1.top, rc1.right, rc1.bottom);
2310
2311     /* test window just high enough for a horizontal scroll bar */
2312     nccalchelper( hwnd, 100, sbheight + 1, &rc1);
2313     ok( rc1.bottom - rc1.top == 1, "Height should be %d size is %ld,%ld - %ld,%ld\n", 
2314             1, rc1.left, rc1.top, rc1.right, rc1.bottom);
2315
2316     /* test window too narrow for a vertical scroll bar */
2317     nccalchelper( hwnd, sbwidth - 1, 100, &rc1);
2318     ok( rc1.right - rc1.left == sbwidth - 1 , "Width should be %d size is %ld,%ld - %ld,%ld\n", 
2319             sbwidth - 1, rc1.left, rc1.top, rc1.right, rc1.bottom);
2320
2321     /* test window just wide enough for a vertical scroll bar */
2322     nccalchelper( hwnd, sbwidth, 100, &rc1);
2323     ok( rc1.right - rc1.left == 0, "Width should be %d size is %ld,%ld - %ld,%ld\n", 
2324             0, rc1.left, rc1.top, rc1.right, rc1.bottom);
2325
2326     /* same test, but with client edge: not enough width */
2327     SetWindowLong( hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE | GetWindowLong( hwnd, GWL_EXSTYLE));
2328     nccalchelper( hwnd, sbwidth, 100, &rc1);
2329     ok( rc1.right - rc1.left == sbwidth - 2 * GetSystemMetrics(SM_CXEDGE),
2330             "Width should be %d size is %ld,%ld - %ld,%ld\n", 
2331             sbwidth - 2 * GetSystemMetrics(SM_CXEDGE), rc1.left, rc1.top, rc1.right, rc1.bottom);
2332
2333     DestroyWindow( hwnd);
2334 }
2335
2336 static void test_SetParent(void)
2337 {
2338     HWND desktop = GetDesktopWindow();
2339     BOOL is_win9x = GetWindowLongPtrW(desktop, GWLP_WNDPROC) == 0;
2340     HWND parent, child1, child2, child3, child4;
2341
2342     parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW,
2343                              100, 100, 200, 200, 0, 0, 0, NULL);
2344     assert(parent != 0);
2345     child1 = CreateWindowExA(0, "static", NULL, WS_CHILD,
2346                              0, 0, 50, 50, parent, 0, 0, NULL);
2347     assert(child1 != 0);
2348     child2 = CreateWindowExA(0, "static", NULL, WS_POPUP,
2349                              0, 0, 50, 50, child1, 0, 0, NULL);
2350     assert(child2 != 0);
2351     child3 = CreateWindowExA(0, "static", NULL, WS_CHILD,
2352                              0, 0, 50, 50, child2, 0, 0, NULL);
2353     assert(child3 != 0);
2354     child4 = CreateWindowExA(0, "static", NULL, WS_POPUP,
2355                              0, 0, 50, 50, child3, 0, 0, NULL);
2356     assert(child4 != 0);
2357
2358     trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
2359            parent, child1, child2, child3, child4);
2360
2361     check_parents(parent, desktop, 0, 0, 0, parent, parent);
2362     check_parents(child1, parent, parent, parent, 0, parent, parent);
2363     check_parents(child2, desktop, parent, parent, parent, child2, parent);
2364     check_parents(child3, child2, child2, child2, 0, child2, parent);
2365     check_parents(child4, desktop, child2, child2, child2, child4, parent);
2366
2367 todo_wine {
2368     ok(!IsChild(desktop, parent), "wrong parent/child %p/%p\n", desktop, parent);
2369     ok(!IsChild(desktop, child1), "wrong parent/child %p/%p\n", desktop, child1);
2370     ok(!IsChild(desktop, child2), "wrong parent/child %p/%p\n", desktop, child2);
2371     ok(!IsChild(desktop, child3), "wrong parent/child %p/%p\n", desktop, child3);
2372     ok(!IsChild(desktop, child4), "wrong parent/child %p/%p\n", desktop, child4);
2373 }
2374
2375     ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
2376 todo_wine {
2377     ok(!IsChild(desktop, child2), "wrong parent/child %p/%p\n", desktop, child2);
2378 }
2379     ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
2380     ok(!IsChild(child1, child2), "wrong parent/child %p/%p\n", child1, child2);
2381     ok(!IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
2382     ok(IsChild(child2, child3), "wrong parent/child %p/%p\n", child2, child3);
2383     ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
2384     ok(!IsChild(child3, child4), "wrong parent/child %p/%p\n", child3, child4);
2385 todo_wine {
2386     ok(!IsChild(desktop, child4), "wrong parent/child %p/%p\n", desktop, child4);
2387 }
2388
2389     if (!is_win9x) /* Win9x doesn't survive this test */
2390     {
2391         ok(!SetParent(parent, child1), "SetParent should fail\n");
2392         ok(!SetParent(child2, child3), "SetParent should fail\n");
2393         ok(SetParent(child1, parent) != 0, "SetParent should not fail\n");
2394         ok(SetParent(parent, child2) != 0, "SetParent should not fail\n");
2395         ok(SetParent(parent, child3) != 0, "SetParent should not fail\n");
2396         ok(!SetParent(child2, parent), "SetParent should fail\n");
2397         ok(SetParent(parent, child4) != 0, "SetParent should not fail\n");
2398
2399         check_parents(parent, child4, child4, 0, 0, child4, parent);
2400         check_parents(child1, parent, parent, parent, 0, child4, parent);
2401         check_parents(child2, desktop, parent, parent, parent, child2, parent);
2402         check_parents(child3, child2, child2, child2, 0, child2, parent);
2403         check_parents(child4, desktop, child2, child2, child2, child4, parent);
2404     }
2405
2406     ok(DestroyWindow(parent), "DestroyWindow() error %ld\n", GetLastError());
2407
2408     ok(!IsWindow(parent), "parent still exists\n");
2409     ok(!IsWindow(child1), "child1 still exists\n");
2410     ok(!IsWindow(child2), "child2 still exists\n");
2411     ok(!IsWindow(child3), "child3 still exists\n");
2412     ok(!IsWindow(child4), "child4 still exists\n");
2413 }
2414
2415 START_TEST(win)
2416 {
2417     pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
2418     pGetWindowInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetWindowInfo" );
2419
2420     hwndMain = CreateWindowExA(0, "static", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);
2421     if (hwndMain)
2422     {
2423         ok(!GetParent(hwndMain), "GetParent should return 0 for message only windows\n");
2424         if (pGetAncestor)
2425         {
2426             hwndMessage = pGetAncestor(hwndMain, GA_PARENT);
2427             ok(hwndMessage != 0, "GetAncestor(GA_PARENT) should not return 0 for message only windows\n");
2428             trace("hwndMessage %p\n", hwndMessage);
2429         }
2430         DestroyWindow(hwndMain);
2431     }
2432     else
2433         trace("CreateWindowExA with parent HWND_MESSAGE failed\n");
2434
2435     if (!RegisterWindowClasses()) assert(0);
2436
2437     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
2438     assert(hhook);
2439
2440     hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
2441                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2442                                WS_MAXIMIZEBOX | WS_POPUP,
2443                                100, 100, 200, 200,
2444                                0, 0, 0, NULL);
2445     hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2",
2446                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
2447                                 WS_MAXIMIZEBOX | WS_POPUP,
2448                                 100, 100, 200, 200,
2449                                 0, 0, 0, NULL);
2450     assert( hwndMain );
2451     assert( hwndMain2 );
2452
2453     test_capture_1();
2454     test_capture_2();
2455     test_capture_3(hwndMain, hwndMain2);
2456
2457     test_parent_owner();
2458     test_SetParent();
2459     test_shell_window();
2460
2461     test_mdi();
2462     test_icons();
2463     test_SetWindowPos(hwndMain);
2464     test_SetMenu(hwndMain);
2465     test_SetFocus(hwndMain);
2466     test_SetActiveWindow(hwndMain);
2467
2468     test_children_zorder(hwndMain);
2469     test_keyboard_input(hwndMain);
2470     test_mouse_input(hwndMain);
2471     test_validatergn(hwndMain);
2472     test_nccalcscroll( hwndMain);
2473
2474     UnhookWindowsHookEx(hhook);
2475 }