Avoid excessive heap memory reallocation when generating EMF
[wine] / dlls / user / tests / win.c
1 /*
2  * Unit tests for window handling
3  *
4  * Copyright 2002 Bill Medland
5  * Copyright 2002 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31
32 #include "wine/test.h"
33
34 #ifndef SPI_GETDESKWALLPAPER
35 #define SPI_GETDESKWALLPAPER 0x0073
36 #endif
37
38 #define LONG_PTR INT_PTR
39 #define ULONG_PTR UINT_PTR
40
41 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
42
43 static HWND hwndMain, hwndMain2;
44
45 /* check the values returned by the various parent/owner functions on a given window */
46 static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent,
47                            HWND gw_owner, HWND ga_root, HWND ga_root_owner )
48 {
49     HWND res;
50
51     if (pGetAncestor)
52     {
53         res = pGetAncestor( hwnd, GA_PARENT );
54         ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p", res, ga_parent );
55     }
56     res = (HWND)GetWindowLongA( hwnd, GWL_HWNDPARENT );
57     ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %p expected %p", res, gwl_parent );
58     res = GetParent( hwnd );
59     ok( res == get_parent, "Wrong result for GetParent %p expected %p", res, get_parent );
60     res = GetWindow( hwnd, GW_OWNER );
61     ok( res == gw_owner, "Wrong result for GW_OWNER %p expected %p", res, gw_owner );
62     if (pGetAncestor)
63     {
64         res = pGetAncestor( hwnd, GA_ROOT );
65         ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p", res, ga_root );
66         res = pGetAncestor( hwnd, GA_ROOTOWNER );
67         ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p", res, ga_root_owner );
68     }
69 }
70
71
72 static HWND create_tool_window( LONG style, HWND parent )
73 {
74     HWND ret = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", style,
75                                0, 0, 100, 100, parent, 0, 0, NULL );
76     ok( ret != 0, "Creation failed" );
77     return ret;
78 }
79
80 /* test parent and owner values for various combinations */
81 static void test_parent_owner(void)
82 {
83     LONG style;
84     HWND test, owner, ret;
85     HWND desktop = GetDesktopWindow();
86     HWND child = create_tool_window( WS_CHILD, hwndMain );
87
88     trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child );
89
90     /* child without parent, should fail */
91     test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1",
92                            WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL );
93     ok( !test, "WS_CHILD without parent created" );
94
95     /* desktop window */
96     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
97     style = GetWindowLongA( desktop, GWL_STYLE );
98     ok( !SetWindowLongA( desktop, GWL_STYLE, WS_POPUP ), "Set GWL_STYLE on desktop succeeded" );
99     ok( !SetWindowLongA( desktop, GWL_STYLE, 0 ), "Set GWL_STYLE on desktop succeeded" );
100     ok( GetWindowLongA( desktop, GWL_STYLE ) == style, "Desktop style changed" );
101
102     /* normal child window */
103     test = create_tool_window( WS_CHILD, hwndMain );
104     trace( "created child %p\n", test );
105     check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain );
106     SetWindowLongA( test, GWL_STYLE, 0 );
107     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
108     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
109     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
110     SetWindowLongA( test, GWL_STYLE, WS_POPUP|WS_CHILD );
111     check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
112     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
113     DestroyWindow( test );
114
115     /* child of desktop */
116     test = create_tool_window( WS_CHILD, desktop );
117     trace( "created child of desktop %p\n", test );
118     check_parents( test, desktop, 0, desktop, 0, test, desktop );
119     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
120     check_parents( test, desktop, 0, 0, 0, test, test );
121     SetWindowLongA( test, GWL_STYLE, 0 );
122     check_parents( test, desktop, 0, 0, 0, test, test );
123     DestroyWindow( test );
124
125     /* child of child */
126     test = create_tool_window( WS_CHILD, child );
127     trace( "created child of child %p\n", test );
128     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
129     SetWindowLongA( test, GWL_STYLE, 0 );
130     check_parents( test, child, child, 0, 0, hwndMain, test );
131     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
132     check_parents( test, child, child, 0, 0, hwndMain, test );
133     DestroyWindow( test );
134
135     /* not owned top-level window */
136     test = create_tool_window( 0, 0 );
137     trace( "created top-level %p\n", test );
138     check_parents( test, desktop, 0, 0, 0, test, test );
139     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
140     check_parents( test, desktop, 0, 0, 0, test, test );
141     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
142     check_parents( test, desktop, 0, desktop, 0, test, desktop );
143     DestroyWindow( test );
144
145     /* owned top-level window */
146     test = create_tool_window( 0, hwndMain );
147     trace( "created owned top-level %p\n", test );
148     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
149     SetWindowLongA( test, GWL_STYLE, WS_POPUP );
150     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
151     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
152     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
153     DestroyWindow( test );
154
155     /* not owned popup */
156     test = create_tool_window( WS_POPUP, 0 );
157     trace( "created popup %p\n", test );
158     check_parents( test, desktop, 0, 0, 0, test, test );
159     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
160     check_parents( test, desktop, 0, desktop, 0, test, desktop );
161     SetWindowLongA( test, GWL_STYLE, 0 );
162     check_parents( test, desktop, 0, 0, 0, test, test );
163     DestroyWindow( test );
164
165     /* owned popup */
166     test = create_tool_window( WS_POPUP, hwndMain );
167     trace( "created owned popup %p\n", test );
168     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
169     SetWindowLongA( test, GWL_STYLE, WS_CHILD );
170     check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
171     SetWindowLongA( test, GWL_STYLE, 0 );
172     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
173     DestroyWindow( test );
174
175     /* top-level window owned by child (same as owned by top-level) */
176     test = create_tool_window( 0, child );
177     trace( "created top-level owned by child %p\n", test );
178     check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
179     DestroyWindow( test );
180
181     /* popup owned by desktop (same as not owned) */
182     test = create_tool_window( WS_POPUP, desktop );
183     trace( "created popup owned by desktop %p\n", test );
184     check_parents( test, desktop, 0, 0, 0, test, test );
185     DestroyWindow( test );
186
187     /* popup owned by child (same as owned by top-level) */
188     test = create_tool_window( WS_POPUP, child );
189     trace( "created popup owned by child %p\n", test );
190     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
191     DestroyWindow( test );
192
193     /* not owned popup with WS_CHILD (same as WS_POPUP only) */
194     test = create_tool_window( WS_POPUP | WS_CHILD, 0 );
195     trace( "created WS_CHILD popup %p\n", test );
196     check_parents( test, desktop, 0, 0, 0, test, test );
197     DestroyWindow( test );
198
199     /* owned popup with WS_CHILD (same as WS_POPUP only) */
200     test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain );
201     trace( "created owned WS_CHILD popup %p\n", test );
202     check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
203     DestroyWindow( test );
204
205     /******************** parent changes *************************/
206     trace( "testing parent changes\n" );
207
208     /* desktop window */
209     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
210     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
211     ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop" );
212     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
213     ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop" );
214     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
215
216     /* normal child window */
217     test = create_tool_window( WS_CHILD, hwndMain );
218     trace( "created child %p\n", test );
219
220     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
221     ok( ret == hwndMain, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain );
222     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
223
224     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
225     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 );
226     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
227
228     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)desktop );
229     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
230     check_parents( test, desktop, 0, desktop, 0, test, desktop );
231
232     /* window is now child of desktop so GWL_HWNDPARENT changes owner from now on */
233     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
234     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
235     check_parents( test, desktop, child, desktop, child, test, desktop );
236
237     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
238     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
239     check_parents( test, desktop, 0, desktop, 0, test, desktop );
240     DestroyWindow( test );
241
242     /* not owned top-level window */
243     test = create_tool_window( 0, 0 );
244     trace( "created top-level %p\n", test );
245
246     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
247     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
248     check_parents( test, desktop, hwndMain2, 0, hwndMain2, test, test );
249
250     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
251     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 );
252     check_parents( test, desktop, child, 0, child, test, test );
253
254     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
255     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
256     check_parents( test, desktop, 0, 0, 0, test, test );
257     DestroyWindow( test );
258
259     /* not owned popup */
260     test = create_tool_window( WS_POPUP, 0 );
261     trace( "created popup %p\n", test );
262
263     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 );
264     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
265     check_parents( test, desktop, hwndMain2, hwndMain2, hwndMain2, test, hwndMain2 );
266
267     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child );
268     ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 );
269     check_parents( test, desktop, child, child, child, test, hwndMain );
270
271     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 );
272     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
273     check_parents( test, desktop, 0, 0, 0, test, test );
274     DestroyWindow( test );
275
276     /* normal child window */
277     test = create_tool_window( WS_CHILD, hwndMain );
278     trace( "created child %p\n", test );
279
280     ret = SetParent( test, desktop );
281     ok( ret == hwndMain, "SetParent return value %p expected %p", ret, hwndMain );
282     check_parents( test, desktop, 0, desktop, 0, test, desktop );
283
284     ret = SetParent( test, child );
285     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
286     check_parents( test, child, child, child, 0, hwndMain, hwndMain );
287
288     ret = SetParent( test, hwndMain2 );
289     ok( ret == child, "SetParent return value %p expected %p", ret, child );
290     check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
291     DestroyWindow( test );
292
293     /* not owned top-level window */
294     test = create_tool_window( 0, 0 );
295     trace( "created top-level %p\n", test );
296
297     ret = SetParent( test, child );
298     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
299     check_parents( test, child, child, 0, 0, hwndMain, test );
300     DestroyWindow( test );
301
302     /* owned popup */
303     test = create_tool_window( WS_POPUP, hwndMain2 );
304     trace( "created owned popup %p\n", test );
305
306     ret = SetParent( test, child );
307     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
308     check_parents( test, child, child, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
309
310     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)hwndMain );
311     ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child );
312     check_parents( test, hwndMain, hwndMain, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
313     DestroyWindow( test );
314
315     /**************** test owner destruction *******************/
316
317     /* owned child popup */
318     owner = create_tool_window( 0, 0 );
319     test = create_tool_window( WS_POPUP, owner );
320     trace( "created owner %p and popup %p\n", owner, test );
321     ret = SetParent( test, child );
322     ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop );
323     check_parents( test, child, child, owner, owner, hwndMain, owner );
324     /* window is now child of 'child' but owned by 'owner' */
325     DestroyWindow( owner );
326     ok( IsWindow(test), "Window %p destroyed by owner destruction", test );
327     check_parents( test, child, child, owner, owner, hwndMain, owner );
328     ok( !IsWindow(owner), "Owner %p not destroyed", owner );
329     DestroyWindow(test);
330
331     /* owned top-level popup */
332     owner = create_tool_window( 0, 0 );
333     test = create_tool_window( WS_POPUP, owner );
334     trace( "created owner %p and popup %p\n", owner, test );
335     check_parents( test, desktop, owner, owner, owner, test, owner );
336     DestroyWindow( owner );
337     ok( !IsWindow(test), "Window %p not destroyed by owner destruction", test );
338
339     /* top-level popup owned by child */
340     owner = create_tool_window( WS_CHILD, hwndMain2 );
341     test = create_tool_window( WS_POPUP, 0 );
342     trace( "created owner %p and popup %p\n", owner, test );
343     ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)owner );
344     ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret );
345     check_parents( test, desktop, owner, owner, owner, test, hwndMain2 );
346     DestroyWindow( owner );
347     ok( IsWindow(test), "Window %p destroyed by owner destruction", test );
348     ok( !IsWindow(owner), "Owner %p not destroyed", owner );
349     check_parents( test, desktop, owner, owner, owner, test, owner );
350     DestroyWindow(test);
351
352     /* final cleanup */
353     DestroyWindow(child);
354 }
355
356
357 static BOOL RegisterWindowClasses(void)
358 {
359     WNDCLASSA cls;
360
361     cls.style = 0;
362     cls.lpfnWndProc = DefWindowProcA;
363     cls.cbClsExtra = 0;
364     cls.cbWndExtra = 0;
365     cls.hInstance = GetModuleHandleA(0);
366     cls.hIcon = 0;
367     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
368     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
369     cls.lpszMenuName = NULL;
370     cls.lpszClassName = "MainWindowClass";
371
372     if(!RegisterClassA(&cls)) return FALSE;
373
374     cls.style = 0;
375     cls.lpfnWndProc = DefWindowProcA;
376     cls.cbClsExtra = 0;
377     cls.cbWndExtra = 0;
378     cls.hInstance = GetModuleHandleA(0);
379     cls.hIcon = 0;
380     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
381     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
382     cls.lpszMenuName = NULL;
383     cls.lpszClassName = "ToolWindowClass";
384
385     if(!RegisterClassA(&cls)) return FALSE;
386
387     return TRUE;
388 }
389
390
391 START_TEST(win)
392 {
393     pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
394
395     if (!RegisterWindowClasses()) assert(0);
396
397     hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
398                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
399                                WS_MAXIMIZEBOX | WS_POPUP,
400                                100, 100, 200, 200,
401                                0, 0, 0, NULL);
402     hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2",
403                                 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
404                                 WS_MAXIMIZEBOX | WS_POPUP,
405                                 100, 100, 200, 200,
406                                 0, 0, 0, NULL);
407     assert( hwndMain );
408     assert( hwndMain2 );
409
410     test_parent_owner();
411 }