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