[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 (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &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 PeekMessage( &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 MINMAXINFO* minmax = (MINMAXINFO *)lparam;
709
710 trace("WM_GETMINMAXINFO: hwnd %p, %08lx, %08lx\n", hwnd, wparam, lparam);
711 dump_minmax_info( minmax );
712 SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0x20031021);
713 break;
714 }
715 case WM_WINDOWPOSCHANGING:
716 {
717 WINDOWPOS *winpos = (WINDOWPOS *)lparam;
718 trace("main: WM_WINDOWPOSCHANGING %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
719 winpos->hwnd, winpos->hwndInsertAfter,
720 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
721 if (!(winpos->flags & SWP_NOMOVE))
722 {
723 ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x);
724 ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y);
725 }
726 /* Win9x does not fixup cx/xy for WM_WINDOWPOSCHANGING */
727 if (!(winpos->flags & SWP_NOSIZE) && !is_win9x)
728 {
729 ok((winpos->cx >= 0 && winpos->cx <= 32767) ||
730 winpos->cx == 32768, /* win7 doesn't truncate */
731 "bad winpos->cx %d\n", winpos->cx);
732 ok((winpos->cy >= 0 && winpos->cy <= 32767) ||
733 winpos->cy == 40000, /* win7 doesn't truncate */
734 "bad winpos->cy %d\n", winpos->cy);
735 }
736 break;
737 }
738 case WM_WINDOWPOSCHANGED:
739 {
740 RECT rc1, rc2;
741 WINDOWPOS *winpos = (WINDOWPOS *)lparam;
742 trace("main: WM_WINDOWPOSCHANGED %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
743 winpos->hwnd, winpos->hwndInsertAfter,
744 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
745 ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x);
746 ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y);
747
748 ok((winpos->cx >= 0 && winpos->cx <= 32767) ||
749 winpos->cx == 32768, /* win7 doesn't truncate */
750 "bad winpos->cx %d\n", winpos->cx);
751 ok((winpos->cy >= 0 && winpos->cy <= 32767) ||
752 winpos->cy == 40000, /* win7 doesn't truncate */
753 "bad winpos->cy %d\n", winpos->cy);
754
755 GetWindowRect(hwnd, &rc1);
756 SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
757 /* note: winpos coordinates are relative to parent */
758 MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
759 if (0)
760 {
761 /* Uncomment this once the test succeeds in all cases */
762 ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
763 rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom );
764
765 GetClientRect(hwnd, &rc2);
766 DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
767 MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
768 ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n",
769 rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom );
770 }
771 break;
772 }
773 case WM_NCCREATE:
774 {
775 BOOL got_getminmaxinfo = GetWindowLongPtrA(hwnd, GWLP_USERDATA) == 0x20031021;
776 CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
777
778 trace("WM_NCCREATE: hwnd %p, parent %p, style %08x\n", hwnd, cs->hwndParent, cs->style);
779 if (got_getminmaxinfo)
780 trace("%p got WM_GETMINMAXINFO\n", hwnd);
781
782 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
783 ok(got_getminmaxinfo, "main: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
784 else
785 ok(!got_getminmaxinfo, "main: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
786 break;
787 }
788 case WM_COMMAND:
789 if (test_lbuttondown_flag)
790 {
791 ShowWindow((HWND)wparam, SW_SHOW);
792 flush_events( FALSE );
793 }
794 break;
795 }
796
797 return DefWindowProcA(hwnd, msg, wparam, lparam);
798 }
799
800 static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
801 {
802 switch (msg)
803 {
804 case WM_GETMINMAXINFO:
805 {
806 MINMAXINFO* minmax = (MINMAXINFO *)lparam;
807
808 trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam);
809 dump_minmax_info( minmax );
810 SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0x20031021);
811 break;
812 }
813 case WM_NCCREATE:
814 {
815 BOOL got_getminmaxinfo = GetWindowLongPtrA(hwnd, GWLP_USERDATA) == 0x20031021;
816 CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
817
818 trace("WM_NCCREATE: hwnd %p, parent %p, style %08x\n", hwnd, cs->hwndParent, cs->style);
819 if (got_getminmaxinfo)
820 trace("%p got WM_GETMINMAXINFO\n", hwnd);
821
822 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
823 ok(got_getminmaxinfo, "tool: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n");
824 else
825 ok(!got_getminmaxinfo, "tool: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n");
826 break;
827 }
828 }
829
830 return DefWindowProcA(hwnd, msg, wparam, lparam);
831 }
832
833 static BOOL RegisterWindowClasses(void)
834 {
835 WNDCLASSA cls;
836
837 cls.style = CS_DBLCLKS;
838 cls.lpfnWndProc = main_window_procA;
839 cls.cbClsExtra = 0;
840 cls.cbWndExtra = 0;
841 cls.hInstance = GetModuleHandleA(0);
842 cls.hIcon = 0;
843 cls.hCursor = LoadCursorA(0, IDC_ARROW);
844 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
845 cls.lpszMenuName = NULL;
846 cls.lpszClassName = "MainWindowClass";
847
848 if(!RegisterClassA(&cls)) return FALSE;
849
850 cls.style = 0;
851 cls.lpfnWndProc = tool_window_procA;
852 cls.cbClsExtra = 0;
853 cls.cbWndExtra = 0;
854 cls.hInstance = GetModuleHandleA(0);
855 cls.hIcon = 0;
856 cls.hCursor = LoadCursorA(0, IDC_ARROW);
857 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
858 cls.lpszMenuName = NULL;
859 cls.lpszClassName = "ToolWindowClass";
860
861 if(!RegisterClassA(&cls)) return FALSE;
862
863 return TRUE;
864 }
865
866 static void verify_window_info(const char *hook, HWND hwnd, const WINDOWINFO *info)
867 {
868 RECT rcWindow, rcClient;
869 DWORD status;
870
871 ok(IsWindow(hwnd), "bad window handle %p in hook %s\n", hwnd, hook);
872
873 GetWindowRect(hwnd, &rcWindow);
874 ok(EqualRect(&rcWindow, &info->rcWindow), "wrong rcWindow for %p in hook %s\n", hwnd, hook);
875
876 GetClientRect(hwnd, &rcClient);
877 /* translate to screen coordinates */
878 MapWindowPoints(hwnd, 0, (LPPOINT)&rcClient, 2);
879 ok(EqualRect(&rcClient, &info->rcClient), "wrong rcClient for %p in hook %s\n", hwnd, hook);
880
881 ok(info->dwStyle == (DWORD)GetWindowLongA(hwnd, GWL_STYLE),
882 "wrong dwStyle: %08x != %08x for %p in hook %s\n",
883 info->dwStyle, GetWindowLongA(hwnd, GWL_STYLE), hwnd, hook);
884 /* Windows reports some undocumented exstyles in WINDOWINFO, but
885 * doesn't return them in GetWindowLong(hwnd, GWL_EXSTYLE).
886 */
887 ok((info->dwExStyle & ~0xe0000800) == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE),
888 "wrong dwExStyle: %08x != %08x for %p in hook %s\n",
889 info->dwExStyle, GetWindowLongA(hwnd, GWL_EXSTYLE), hwnd, hook);
890 status = (GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0;
891 if (GetForegroundWindow())
892 ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04x != %04x active %p fg %p in hook %s\n",
893 info->dwWindowStatus, status, GetActiveWindow(), GetForegroundWindow(), hook);
894
895 /* win2k and XP return broken border info in GetWindowInfo most of
896 * the time, so there is no point in testing it.
897 */
898 #if 0
899 UINT border;
900 ok(info->cxWindowBorders == (unsigned)(rcClient.left - rcWindow.left),
901 "wrong cxWindowBorders %d != %d\n", info->cxWindowBorders, rcClient.left - rcWindow.left);
902 border = min(rcWindow.bottom - rcClient.bottom, rcClient.top - rcWindow.top);
903 ok(info->cyWindowBorders == border,
904 "wrong cyWindowBorders %d != %d\n", info->cyWindowBorders, border);
905 #endif
906 ok(info->atomWindowType == GetClassLongA(hwnd, GCW_ATOM), "wrong atomWindowType for %p in hook %s\n",
907 hwnd, hook);
908 ok(info->wCreatorVersion == 0x0400 /* NT4, Win2000, XP, Win2003 */ ||
909 info->wCreatorVersion == 0x0500 /* Vista */,
910 "wrong wCreatorVersion %04x for %p in hook %s\n", info->wCreatorVersion, hwnd, hook);
911 }
912
913 static void FixedAdjustWindowRectEx(RECT* rc, LONG style, BOOL menu, LONG exstyle)
914 {
915 AdjustWindowRectEx(rc, style, menu, exstyle);
916 /* AdjustWindowRectEx does not include scroll bars */
917 if (style & WS_VSCROLL)
918 {
919 if(exstyle & WS_EX_LEFTSCROLLBAR)
920 rc->left -= GetSystemMetrics(SM_CXVSCROLL);
921 else
922 rc->right += GetSystemMetrics(SM_CXVSCROLL);
923 }
924 if (style & WS_HSCROLL)
925 rc->bottom += GetSystemMetrics(SM_CYHSCROLL);
926 }
927
928 static void test_nonclient_area(HWND hwnd)
929 {
930 DWORD style, exstyle;
931 RECT rc_window, rc_client, rc;
932 BOOL menu;
933 LRESULT ret;
934
935 style = GetWindowLongA(hwnd, GWL_STYLE);
936 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
937 menu = !(style & WS_CHILD) && GetMenu(hwnd) != 0;
938
939 GetWindowRect(hwnd, &rc_window);
940 GetClientRect(hwnd, &rc_client);
941
942 /* avoid some cases when things go wrong */
943 if (IsRectEmpty(&rc_window) || IsRectEmpty(&rc_client) ||
944 rc_window.right > 32768 || rc_window.bottom > 32768) return;
945
946 CopyRect(&rc, &rc_client);
947 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
948 FixedAdjustWindowRectEx(&rc, style, menu, exstyle);
949
950 ok(EqualRect(&rc, &rc_window),
951 "window rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, win=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n",
952 style, exstyle, menu, rc_window.left, rc_window.top, rc_window.right, rc_window.bottom,
953 rc.left, rc.top, rc.right, rc.bottom);
954
955
956 CopyRect(&rc, &rc_window);
957 DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
958 MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2);
959 ok(EqualRect(&rc, &rc_client),
960 "client rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d client=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n",
961 style, exstyle, menu, rc_client.left, rc_client.top, rc_client.right, rc_client.bottom,
962 rc.left, rc.top, rc.right, rc.bottom);
963
964 /* NULL rectangle shouldn't crash */
965 ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, 0);
966 ok(ret == 0, "NULL rectangle returned %ld instead of 0\n", ret);
967
968 /* Win9x doesn't like WM_NCCALCSIZE with synthetic data and crashes */;
969 if (is_win9x)
970 return;
971
972 /* and now test AdjustWindowRectEx and WM_NCCALCSIZE on synthetic data */
973 SetRect(&rc_client, 0, 0, 250, 150);
974 CopyRect(&rc_window, &rc_client);
975 MapWindowPoints(hwnd, 0, (LPPOINT)&rc_window, 2);
976 FixedAdjustWindowRectEx(&rc_window, style, menu, exstyle);
977
978 CopyRect(&rc, &rc_window);
979 DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
980 MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2);
981 ok(EqualRect(&rc, &rc_client),
982 "synthetic rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, client=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n",
983 style, exstyle, menu, rc_client.left, rc_client.top, rc_client.right, rc_client.bottom,
984 rc.left, rc.top, rc.right, rc.bottom);
985 }
986
987 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
988 {
989 static const char *CBT_code_name[10] = {
990 "HCBT_MOVESIZE",
991 "HCBT_MINMAX",
992 "HCBT_QS",
993 "HCBT_CREATEWND",
994 "HCBT_DESTROYWND",
995 "HCBT_ACTIVATE",
996 "HCBT_CLICKSKIPPED",
997 "HCBT_KEYSKIPPED",
998 "HCBT_SYSCOMMAND",
999 "HCBT_SETFOCUS" };
1000 const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
1001 HWND hwnd = (HWND)wParam;
1002
1003 switch (nCode)
1004 {
1005 case HCBT_CREATEWND:
1006 {
1007 static const RECT rc_null;
1008 RECT rc;
1009 LONG style;
1010 CBT_CREATEWNDA *createwnd = (CBT_CREATEWNDA *)lParam;
1011 ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n");
1012
1013 if (pGetWindowInfo)
1014 {
1015 WINDOWINFO info;
1016 info.cbSize = sizeof(WINDOWINFO);
1017 ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n");
1018 verify_window_info(code_name, hwnd, &info);
1019 }
1020
1021 /* WS_VISIBLE should be turned off yet */
1022 style = createwnd->lpcs->style & ~WS_VISIBLE;
1023 ok(style == GetWindowLongA(hwnd, GWL_STYLE),
1024 "style of hwnd and style in the CREATESTRUCT do not match: %08x != %08x\n",
1025 GetWindowLongA(hwnd, GWL_STYLE), style);
1026
1027 if (0)
1028 {
1029 /* Uncomment this once the test succeeds in all cases */
1030 if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1031 {
1032 ok(GetParent(hwnd) == hwndMessage,
1033 "wrong result from GetParent %p: message window %p\n",
1034 GetParent(hwnd), hwndMessage);
1035 }
1036 else
1037 ok(!GetParent(hwnd), "GetParent should return 0 at this point\n");
1038
1039 ok(!GetWindow(hwnd, GW_OWNER), "GW_OWNER should be set to 0 at this point\n");
1040 }
1041 if (0)
1042 {
1043 /* while NT assigns GW_HWNDFIRST/LAST some values at this point,
1044 * Win9x still has them set to 0.
1045 */
1046 ok(GetWindow(hwnd, GW_HWNDFIRST) != 0, "GW_HWNDFIRST should not be set to 0 at this point\n");
1047 ok(GetWindow(hwnd, GW_HWNDLAST) != 0, "GW_HWNDLAST should not be set to 0 at this point\n");
1048 }
1049 ok(!GetWindow(hwnd, GW_HWNDPREV), "GW_HWNDPREV should be set to 0 at this point\n");
1050 ok(!GetWindow(hwnd, GW_HWNDNEXT), "GW_HWNDNEXT should be set to 0 at this point\n");
1051
1052 if (0)
1053 {
1054 /* Uncomment this once the test succeeds in all cases */
1055 if (pGetAncestor)
1056 {
1057 ok(pGetAncestor(hwnd, GA_PARENT) == hwndMessage, "GA_PARENT should be set to hwndMessage at this point\n");
1058 ok(pGetAncestor(hwnd, GA_ROOT) == hwnd,
1059 "GA_ROOT is set to %p, expected %p\n", pGetAncestor(hwnd, GA_ROOT), hwnd);
1060
1061 if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1062 ok(pGetAncestor(hwnd, GA_ROOTOWNER) == hwndMessage,
1063 "GA_ROOTOWNER should be set to hwndMessage at this point\n");
1064 else
1065 ok(pGetAncestor(hwnd, GA_ROOTOWNER) == hwnd,
1066 "GA_ROOTOWNER is set to %p, expected %p\n", pGetAncestor(hwnd, GA_ROOTOWNER), hwnd);
1067 }
1068
1069 ok(GetWindowRect(hwnd, &rc), "GetWindowRect failed\n");
1070 ok(EqualRect(&rc, &rc_null), "window rect should be set to 0 HCBT_CREATEWND\n");
1071 ok(GetClientRect(hwnd, &rc), "GetClientRect failed\n");
1072 ok(EqualRect(&rc, &rc_null), "client rect should be set to 0 on HCBT_CREATEWND\n");
1073 }
1074 break;
1075 }
1076 case HCBT_MOVESIZE:
1077 case HCBT_MINMAX:
1078 case HCBT_ACTIVATE:
1079 if (pGetWindowInfo && IsWindow(hwnd))
1080 {
1081 WINDOWINFO info;
1082
1083 /* Win98 actually does check the info.cbSize and doesn't allow
1084 * it to be anything except sizeof(WINDOWINFO), while Win95, Win2k,
1085 * WinXP do not check it at all.
1086 */
1087 info.cbSize = sizeof(WINDOWINFO);
1088 ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n");
1089 verify_window_info(code_name, hwnd, &info);
1090 }
1091 break;
1092 /* window state is undefined */
1093 case HCBT_SETFOCUS:
1094 case HCBT_DESTROYWND:
1095 break;
1096 default:
1097 break;
1098 }
1099
1100 return CallNextHookEx(hhook, nCode, wParam, lParam);
1101 }
1102
1103 static void test_shell_window(void)
1104 {
1105 BOOL ret;
1106 DWORD error;
1107 HMODULE hinst, hUser32;
1108 BOOL (WINAPI*SetShellWindow)(HWND);
1109 HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5;
1110 HWND shellWindow, nextWnd;
1111
1112 if (is_win9x)
1113 {
1114 win_skip("Skipping shell window test on Win9x\n");
1115 return;
1116 }
1117
1118 shellWindow = GetShellWindow();
1119 hinst = GetModuleHandle(0);
1120 hUser32 = GetModuleHandleA("user32");
1121
1122 SetShellWindow = (void *)GetProcAddress(hUser32, "SetShellWindow");
1123
1124 trace("previous shell window: %p\n", shellWindow);
1125
1126 if (shellWindow) {
1127 DWORD pid;
1128 HANDLE hProcess;
1129
1130 GetWindowThreadProcessId(shellWindow, &pid);
1131 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
1132 if (!hProcess)
1133 {
1134 skip( "cannot get access to shell process\n" );
1135 return;
1136 }
1137
1138 SetLastError(0xdeadbeef);
1139 ret = DestroyWindow(shellWindow);
1140 error = GetLastError();
1141
1142 ok(!ret, "DestroyWindow(shellWindow)\n");
1143 /* passes on Win XP, but not on Win98 */
1144 ok(error==ERROR_ACCESS_DENIED || error == 0xdeadbeef,
1145 "got %u after DestroyWindow(shellWindow)\n", error);
1146
1147 /* close old shell instance */
1148 ret = TerminateProcess(hProcess, 0);
1149 ok(ret, "termination of previous shell process failed: GetLastError()=%d\n", GetLastError());
1150 WaitForSingleObject(hProcess, INFINITE); /* wait for termination */
1151 CloseHandle(hProcess);
1152 }
1153
1154 hwnd1 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0);
1155 trace("created window 1: %p\n", hwnd1);
1156
1157 ret = SetShellWindow(hwnd1);
1158 ok(ret, "first call to SetShellWindow(hwnd1)\n");
1159 shellWindow = GetShellWindow();
1160 ok(shellWindow==hwnd1, "wrong shell window: %p\n", shellWindow);
1161
1162 ret = SetShellWindow(hwnd1);
1163 ok(!ret, "second call to SetShellWindow(hwnd1)\n");
1164
1165 ret = SetShellWindow(0);
1166 error = GetLastError();
1167 /* passes on Win XP, but not on Win98
1168 ok(!ret, "reset shell window by SetShellWindow(0)\n");
1169 ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */
1170
1171 ret = SetShellWindow(hwnd1);
1172 /* passes on Win XP, but not on Win98
1173 ok(!ret, "third call to SetShellWindow(hwnd1)\n"); */
1174
1175 SetWindowLong(hwnd1, GWL_EXSTYLE, GetWindowLong(hwnd1,GWL_EXSTYLE)|WS_EX_TOPMOST);
1176 ret = (GetWindowLong(hwnd1,GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
1177 ok(!ret, "SetWindowExStyle(hwnd1, WS_EX_TOPMOST)\n");
1178
1179 ret = DestroyWindow(hwnd1);
1180 ok(ret, "DestroyWindow(hwnd1)\n");
1181
1182 hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0);
1183 trace("created window 2: %p\n", hwnd2);
1184 ret = SetShellWindow(hwnd2);
1185 ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST\n");
1186
1187 hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0);
1188 trace("created window 3: %p\n", hwnd3);
1189
1190 hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0);
1191 trace("created window 4: %p\n", hwnd4);
1192
1193 nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
1194 ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd);
1195
1196 ret = SetShellWindow(hwnd4);
1197 ok(ret, "SetShellWindow(hwnd4)\n");
1198 shellWindow = GetShellWindow();
1199 ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow);
1200
1201 nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
1202 ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd);
1203
1204 ret = SetWindowPos(hwnd4, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1205 ok(ret, "SetWindowPos(hwnd4, HWND_TOPMOST)\n");
1206
1207 ret = SetWindowPos(hwnd4, hwnd3, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1208 ok(ret, "SetWindowPos(hwnd4, hwnd3\n");
1209
1210 ret = SetShellWindow(hwnd3);
1211 ok(!ret, "SetShellWindow(hwnd3)\n");
1212 shellWindow = GetShellWindow();
1213 ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow);
1214
1215 hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0);
1216 trace("created window 5: %p\n", hwnd5);
1217 ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1218 ok(ret, "SetWindowPos(hwnd4, hwnd5)\n");
1219
1220 todo_wine
1221 {
1222 nextWnd = GetWindow(hwnd4, GW_HWNDNEXT);
1223 ok(nextWnd==0, "wrong next window for hwnd4 after SetWindowPos(): %p - expected 0\n", nextWnd);
1224 }
1225
1226 /* destroy test windows */
1227 DestroyWindow(hwnd2);
1228 DestroyWindow(hwnd3);
1229 DestroyWindow(hwnd4);
1230 DestroyWindow(hwnd5);
1231 }
1232
1233 /************** MDI test ****************/
1234
1235 static char mdi_lParam_test_message[] = "just a test string";
1236
1237 static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
1238 {
1239 MDICREATESTRUCTA mdi_cs;
1240 HWND mdi_child;
1241 INT_PTR id;
1242 static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0};
1243 static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0};
1244 BOOL isWin9x = FALSE;
1245
1246 mdi_cs.szClass = "MDI_child_Class_1";
1247 mdi_cs.szTitle = "MDI child";
1248 mdi_cs.hOwner = GetModuleHandle(0);
1249 mdi_cs.x = CW_USEDEFAULT;
1250 mdi_cs.y = CW_USEDEFAULT;
1251 mdi_cs.cx = CW_USEDEFAULT;
1252 mdi_cs.cy = CW_USEDEFAULT;
1253 mdi_cs.style = 0;
1254 mdi_cs.lParam = (LPARAM)mdi_lParam_test_message;
1255 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
1256 ok(mdi_child != 0, "MDI child creation failed\n");
1257 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1258 ok(id == first_id, "wrong child id %ld\n", id);
1259 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1260 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1261
1262 mdi_cs.style = 0x7fffffff; /* without WS_POPUP */
1263 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
1264 ok(mdi_child != 0, "MDI child creation failed\n");
1265 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1266 ok(id == first_id, "wrong child id %ld\n", id);
1267 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1268 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1269
1270 mdi_cs.style = 0xffffffff; /* with WS_POPUP */
1271 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
1272 if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1273 {
1274 ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
1275 }
1276 else
1277 {
1278 ok(mdi_child != 0, "MDI child creation failed\n");
1279 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1280 ok(id == first_id, "wrong child id %ld\n", id);
1281 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1282 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1283 }
1284
1285 /* test MDICREATESTRUCT A<->W mapping */
1286 /* MDICREATESTRUCTA and MDICREATESTRUCTW have the same layout */
1287 mdi_cs.style = 0;
1288 mdi_cs.szClass = (LPCSTR)classW;
1289 mdi_cs.szTitle = (LPCSTR)titleW;
1290 SetLastError(0xdeadbeef);
1291 mdi_child = (HWND)SendMessageW(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
1292 if (!mdi_child)
1293 {
1294 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1295 isWin9x = TRUE;
1296 else
1297 ok(mdi_child != 0, "MDI child creation failed\n");
1298 }
1299 else
1300 {
1301 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1302 ok(id == first_id, "wrong child id %ld\n", id);
1303 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1304 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1305 }
1306
1307 mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
1308 0,
1309 CW_USEDEFAULT, CW_USEDEFAULT,
1310 CW_USEDEFAULT, CW_USEDEFAULT,
1311 mdi_client, GetModuleHandle(0),
1312 (LPARAM)mdi_lParam_test_message);
1313 ok(mdi_child != 0, "MDI child creation failed\n");
1314 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1315 ok(id == first_id, "wrong child id %ld\n", id);
1316 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1317 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1318
1319 mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
1320 0x7fffffff, /* without WS_POPUP */
1321 CW_USEDEFAULT, CW_USEDEFAULT,
1322 CW_USEDEFAULT, CW_USEDEFAULT,
1323 mdi_client, GetModuleHandle(0),
1324 (LPARAM)mdi_lParam_test_message);
1325 ok(mdi_child != 0, "MDI child creation failed\n");
1326 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1327 ok(id == first_id, "wrong child id %ld\n", id);
1328 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1329 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1330
1331 mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
1332 0xffffffff, /* with WS_POPUP */
1333 CW_USEDEFAULT, CW_USEDEFAULT,
1334 CW_USEDEFAULT, CW_USEDEFAULT,
1335 mdi_client, GetModuleHandle(0),
1336 (LPARAM)mdi_lParam_test_message);
1337 if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1338 {
1339 ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
1340 }
1341 else
1342 {
1343 ok(mdi_child != 0, "MDI child creation failed\n");
1344 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1345 ok(id == first_id, "wrong child id %ld\n", id);
1346 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1347 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1348 }
1349
1350 /* test MDICREATESTRUCT A<->W mapping */
1351 SetLastError(0xdeadbeef);
1352 mdi_child = CreateMDIWindowW(classW, titleW,
1353 0,
1354 CW_USEDEFAULT, CW_USEDEFAULT,
1355 CW_USEDEFAULT, CW_USEDEFAULT,
1356 mdi_client, GetModuleHandle(0),
1357 (LPARAM)mdi_lParam_test_message);
1358 if (!mdi_child)
1359 {
1360 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1361 isWin9x = TRUE;
1362 else
1363 ok(mdi_child != 0, "MDI child creation failed\n");
1364 }
1365 else
1366 {
1367 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1368 ok(id == first_id, "wrong child id %ld\n", id);
1369 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1370 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1371 }
1372
1373 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
1374 0,
1375 CW_USEDEFAULT, CW_USEDEFAULT,
1376 CW_USEDEFAULT, CW_USEDEFAULT,
1377 mdi_client, 0, GetModuleHandle(0),
1378 mdi_lParam_test_message);
1379 ok(mdi_child != 0, "MDI child creation failed\n");
1380 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1381 ok(id == first_id, "wrong child id %ld\n", id);
1382 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1383 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1384
1385 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
1386 0x7fffffff, /* without WS_POPUP */
1387 CW_USEDEFAULT, CW_USEDEFAULT,
1388 CW_USEDEFAULT, CW_USEDEFAULT,
1389 mdi_client, 0, GetModuleHandle(0),
1390 mdi_lParam_test_message);
1391 ok(mdi_child != 0, "MDI child creation failed\n");
1392 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1393 ok(id == first_id, "wrong child id %ld\n", id);
1394 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1395 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1396
1397 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
1398 0xffffffff, /* with WS_POPUP */
1399 CW_USEDEFAULT, CW_USEDEFAULT,
1400 CW_USEDEFAULT, CW_USEDEFAULT,
1401 mdi_client, 0, GetModuleHandle(0),
1402 mdi_lParam_test_message);
1403 if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1404 {
1405 ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
1406 }
1407 else
1408 {
1409 ok(mdi_child != 0, "MDI child creation failed\n");
1410 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1411 ok(id == first_id, "wrong child id %ld\n", id);
1412 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1413 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1414 }
1415
1416 /* test MDICREATESTRUCT A<->W mapping */
1417 SetLastError(0xdeadbeef);
1418 mdi_child = CreateWindowExW(WS_EX_MDICHILD, classW, titleW,
1419 0,
1420 CW_USEDEFAULT, CW_USEDEFAULT,
1421 CW_USEDEFAULT, CW_USEDEFAULT,
1422 mdi_client, 0, GetModuleHandle(0),
1423 mdi_lParam_test_message);
1424 if (!mdi_child)
1425 {
1426 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1427 isWin9x = TRUE;
1428 else
1429 ok(mdi_child != 0, "MDI child creation failed\n");
1430 }
1431 else
1432 {
1433 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1434 ok(id == first_id, "wrong child id %ld\n", id);
1435 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
1436 ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
1437 }
1438
1439 /* This test fails on Win9x */
1440 if (!isWin9x)
1441 {
1442 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child",
1443 WS_CHILD,
1444 CW_USEDEFAULT, CW_USEDEFAULT,
1445 CW_USEDEFAULT, CW_USEDEFAULT,
1446 parent, 0, GetModuleHandle(0),
1447 mdi_lParam_test_message);
1448 ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n");
1449 }
1450
1451 mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1452 WS_CHILD, /* without WS_POPUP */
1453 CW_USEDEFAULT, CW_USEDEFAULT,
1454 CW_USEDEFAULT, CW_USEDEFAULT,
1455 mdi_client, 0, GetModuleHandle(0),
1456 mdi_lParam_test_message);
1457 ok(mdi_child != 0, "MDI child creation failed\n");
1458 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1459 ok(id == 0, "wrong child id %ld\n", id);
1460 DestroyWindow(mdi_child);
1461
1462 mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1463 WS_CHILD | WS_POPUP, /* with WS_POPUP */
1464 CW_USEDEFAULT, CW_USEDEFAULT,
1465 CW_USEDEFAULT, CW_USEDEFAULT,
1466 mdi_client, 0, GetModuleHandle(0),
1467 mdi_lParam_test_message);
1468 ok(mdi_child != 0, "MDI child creation failed\n");
1469 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1470 ok(id == 0, "wrong child id %ld\n", id);
1471 DestroyWindow(mdi_child);
1472
1473 /* maximized child */
1474 mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1475 WS_CHILD | WS_MAXIMIZE,
1476 CW_USEDEFAULT, CW_USEDEFAULT,
1477 CW_USEDEFAULT, CW_USEDEFAULT,
1478 mdi_client, 0, GetModuleHandle(0),
1479 mdi_lParam_test_message);
1480 ok(mdi_child != 0, "MDI child creation failed\n");
1481 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1482 ok(id == 0, "wrong child id %ld\n", id);
1483 DestroyWindow(mdi_child);
1484
1485 trace("Creating maximized child with a caption\n");
1486 mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1487 WS_CHILD | WS_MAXIMIZE | WS_CAPTION,
1488 CW_USEDEFAULT, CW_USEDEFAULT,
1489 CW_USEDEFAULT, CW_USEDEFAULT,
1490 mdi_client, 0, GetModuleHandle(0),
1491 mdi_lParam_test_message);
1492 ok(mdi_child != 0, "MDI child creation failed\n");
1493 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1494 ok(id == 0, "wrong child id %ld\n", id);
1495 DestroyWindow(mdi_child);
1496
1497 trace("Creating maximized child with a caption and a thick frame\n");
1498 mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
1499 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
1500 CW_USEDEFAULT, CW_USEDEFAULT,
1501 CW_USEDEFAULT, CW_USEDEFAULT,
1502 mdi_client, 0, GetModuleHandle(0),
1503 mdi_lParam_test_message);
1504 ok(mdi_child != 0, "MDI child creation failed\n");
1505 id = GetWindowLongPtrA(mdi_child, GWLP_ID);
1506 ok(id == 0, "wrong child id %ld\n", id);
1507 DestroyWindow(mdi_child);
1508 }
1509
1510 static void test_MDI_child_stack(HWND mdi_client)
1511 {
1512 HWND child_1, child_2, child_3, child_4;
1513 HWND stack[4];
1514 MDICREATESTRUCTA cs;
1515
1516 cs.szClass = "MDI_child_Class_1";
1517 cs.szTitle = "MDI child";
1518 cs.hOwner = GetModuleHandleA(0);
1519 cs.x = CW_USEDEFAULT;
1520 cs.y = CW_USEDEFAULT;
1521 cs.cx = CW_USEDEFAULT;
1522 cs.cy = CW_USEDEFAULT;
1523 cs.style = 0;
1524 cs.lParam = (LPARAM)mdi_lParam_test_message;
1525
1526 child_1 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
1527 ok(child_1 != 0, "expected child_1 to be non NULL\n");
1528 child_2 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
1529 ok(child_2 != 0, "expected child_2 to be non NULL\n");
1530 child_3 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
1531 ok(child_3 != 0, "expected child_3 to be non NULL\n");
1532 child_4 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
1533 ok(child_4 != 0, "expected child_4 to be non NULL\n");
1534
1535 stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
1536 stack[1] = GetWindow(stack[0], GW_HWNDNEXT);
1537 stack[2] = GetWindow(stack[1], GW_HWNDNEXT);
1538 stack[3] = GetWindow(stack[2], GW_HWNDNEXT);
1539 trace("Initial MDI child stack: %p->%p->%p->%p\n", stack[0], stack[1], stack[2], stack[3]);
1540 ok(stack[0] == child_4 && stack[1] == child_3 &&
1541 stack[2] == child_2 && stack[3] == child_1,
1542 "Unexpected initial order, should be: %p->%p->%p->%p\n",
1543 child_4, child_3, child_2, child_1);
1544
1545 trace("Activate child next to %p\n", child_3);
1546 SendMessage(mdi_client, WM_MDINEXT, (WPARAM)child_3, 0);
1547
1548 stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
1549 stack[1] = GetWindow(stack[0], GW_HWNDNEXT);
1550 stack[2] = GetWindow(stack[1], GW_HWNDNEXT);
1551 stack[3] = GetWindow(stack[2], GW_HWNDNEXT);
1552 ok(stack[0] == child_2 && stack[1] == child_4 &&
1553 stack[2] == child_1 && stack[3] == child_3,
1554 "Broken MDI child stack:\nexpected: %p->%p->%p->%p, but got: %p->%p->%p->%p\n",
1555 child_2, child_4, child_1, child_3, stack[0], stack[1], stack[2], stack[3]);
1556
1557 trace("Activate child previous to %p\n", child_1);
1558 SendMessage(mdi_client, WM_MDINEXT, (WPARAM)child_1, 1);
1559
1560 stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
1561 stack[1] = GetWindow(stack[0], GW_HWNDNEXT);
1562 stack[2] = GetWindow(stack[1], GW_HWNDNEXT);
1563 stack[3] = GetWindow(stack[2], GW_HWNDNEXT);
1564 ok(stack[0] == child_4 && stack[1] == child_2 &&
1565 stack[2] == child_1 && stack[3] == child_3,
1566 "Broken MDI child stack:\nexpected: %p->%p->%p->%p, but got: %p->%p->%p->%p\n",
1567 child_4, child_2, child_1, child_3, stack[0], stack[1], stack[2], stack[3]);
1568
1569 DestroyWindow(child_1);
1570 DestroyWindow(child_2);
1571 DestroyWindow(child_3);
1572 DestroyWindow(child_4);
1573 }
1574
1575 /**********************************************************************
1576 * MDI_ChildGetMinMaxInfo (copied from windows/mdi.c)
1577 *
1578 * Note: The rule here is that client rect of the maximized MDI child
1579 * is equal to the client rect of the MDI client window.
1580 */
1581 static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax )
1582 {
1583 RECT rect;
1584
1585 GetClientRect( client, &rect );
1586 AdjustWindowRectEx( &rect, GetWindowLongA( hwnd, GWL_STYLE ),
1587 0, GetWindowLongA( hwnd, GWL_EXSTYLE ));
1588
1589 rect.right -= rect.left;
1590 rect.bottom -= rect.top;
1591 lpMinMax->ptMaxSize.x = rect.right;
1592 lpMinMax->ptMaxSize.y = rect.bottom;
1593
1594 lpMinMax->ptMaxPosition.x = rect.left;
1595 lpMinMax->ptMaxPosition.y = rect.top;
1596
1597 trace("max rect (%d,%d - %d, %d)\n",
1598 rect.left, rect.top, rect.right, rect.bottom);
1599 }
1600
1601 static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1602 {
1603 switch (msg)
1604 {
1605 case WM_NCCREATE:
1606 case WM_CREATE:
1607 {
1608 CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
1609 MDICREATESTRUCTA *mdi_cs = cs->lpCreateParams;
1610
1611 ok(cs->dwExStyle & WS_EX_MDICHILD, "WS_EX_MDICHILD should be set\n");
1612 ok(mdi_cs->lParam == (LPARAM)mdi_lParam_test_message, "wrong mdi_cs->lParam\n");
1613
1614 ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_1"), "wrong class name\n");
1615 ok(!lstrcmpA(cs->lpszClass, mdi_cs->szClass), "class name does not match\n");
1616 ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
1617 ok(!lstrcmpA(cs->lpszName, mdi_cs->szTitle), "title does not match\n");
1618 ok(cs->hInstance == mdi_cs->hOwner, "%p != %p\n", cs->hInstance, mdi_cs->hOwner);
1619
1620 /* MDICREATESTRUCT should have original values */
1621 ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff,
1622 "mdi_cs->style does not match (%08x)\n", mdi_cs->style);
1623 ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x);
1624 ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y);
1625 ok(mdi_cs->cx == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cx);
1626 ok(mdi_cs->cy == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cy);
1627
1628 /* CREATESTRUCT should have fixed values */
1629 ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);
1630 ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
1631
1632 /* cx/cy == CW_USEDEFAULT are translated to NOT zero values */
1633 ok(cs->cx != CW_USEDEFAULT && cs->cx != 0, "%d == CW_USEDEFAULT\n", cs->cx);
1634 ok(cs->cy != CW_USEDEFAULT && cs->cy != 0, "%d == CW_USEDEFAULT\n", cs->cy);
1635
1636 ok(!(cs->style & WS_POPUP), "WS_POPUP is not allowed\n");
1637
1638 if (GetWindowLongA(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1639 {
1640 LONG style = mdi_cs->style | WS_CHILD | WS_CLIPSIBLINGS;
1641 ok(cs->style == style,
1642 "cs->style does not match (%08x)\n", cs->style);
1643 }
1644 else
1645 {
1646 LONG style = mdi_cs->style;
1647 style &= ~WS_POPUP;
1648 style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1649 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1650 ok(cs->style == style,
1651 "cs->style does not match (%08x)\n", cs->style);
1652 }
1653 break;
1654 }
1655
1656 case WM_GETMINMAXINFO:
1657 {
1658 HWND client = GetParent(hwnd);
1659 RECT rc;
1660 MINMAXINFO *minmax = (MINMAXINFO *)lparam;
1661 MINMAXINFO my_minmax;
1662 LONG style, exstyle;
1663
1664 style = GetWindowLongA(hwnd, GWL_STYLE);
1665 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1666
1667 GetWindowRect(client, &rc);
1668 trace("MDI client %p window size = (%d x %d)\n", client, rc.right-rc.left, rc.bottom-rc.top);
1669 GetClientRect(client, &rc);
1670 trace("MDI client %p client size = (%d x %d)\n", client, rc.right, rc.bottom);
1671 trace("screen size: %d x %d\n", GetSystemMetrics(SM_CXSCREEN),
1672 GetSystemMetrics(SM_CYSCREEN));
1673
1674 GetClientRect(client, &rc);
1675 if ((style & WS_CAPTION) == WS_CAPTION)
1676 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
1677 AdjustWindowRectEx(&rc, style, 0, exstyle);
1678 trace("MDI child: calculated max window size = (%d x %d)\n", rc.right-rc.left, rc.bottom-rc.top);
1679 dump_minmax_info( minmax );
1680
1681 ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n",
1682 minmax->ptMaxSize.x, rc.right - rc.left);
1683 ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %d != %d\n",
1684 minmax->ptMaxSize.y, rc.bottom - rc.top);
1685
1686 DefMDIChildProcA(hwnd, msg, wparam, lparam);
1687
1688 trace("DefMDIChildProc returned:\n");
1689 dump_minmax_info( minmax );
1690
1691 MDI_ChildGetMinMaxInfo(client, hwnd, &my_minmax);
1692 ok(minmax->ptMaxSize.x == my_minmax.ptMaxSize.x, "default width of maximized child %d != %d\n",
1693 minmax->ptMaxSize.x, my_minmax.ptMaxSize.x);
1694 ok(minmax->ptMaxSize.y == my_minmax.ptMaxSize.y, "default height of maximized child %d != %d\n",
1695 minmax->ptMaxSize.y, my_minmax.ptMaxSize.y);
1696
1697 return 1;
1698 }
1699
1700 case WM_MDIACTIVATE:
1701 {
1702 HWND active, client = GetParent(hwnd);
1703 /*trace("%p WM_MDIACTIVATE %08x %08lx\n", hwnd, wparam, lparam);*/
1704 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
1705 if (hwnd == (HWND)lparam) /* if we are being activated */
1706 ok (active == (HWND)lparam, "new active %p != active %p\n", (HWND)lparam, active);
1707 else
1708 ok (active == (HWND)wparam, "old active %p != active %p\n", (HWND)wparam, active);
1709 break;
1710 }
1711 }
1712 return DefMDIChildProcA(hwnd, msg, wparam, lparam);
1713 }
1714
1715 static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1716 {
1717 switch (msg)
1718 {
1719 case WM_NCCREATE:
1720 case WM_CREATE:
1721 {
1722 CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
1723
1724 trace("%s: x %d, y %d, cx %d, cy %d\n", (msg == WM_NCCREATE) ? "WM_NCCREATE" : "WM_CREATE",
1725 cs->x, cs->y, cs->cx, cs->cy);
1726
1727 ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n");
1728 ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n");
1729
1730 ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_2"), "wrong class name\n");
1731 ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
1732
1733 /* CREATESTRUCT should have fixed values */
1734 /* For some reason Win9x doesn't translate cs->x from CW_USEDEFAULT,
1735 while NT does. */
1736 /*ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);*/
1737 ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
1738
1739 /* cx/cy == CW_USEDEFAULT are translated to 0 */
1740 /* For some reason Win98 doesn't translate cs->cx from CW_USEDEFAULT,
1741 while Win95, Win2k, WinXP do. */
1742 /*ok(cs->cx == 0, "%d != 0\n", cs->cx);*/
1743 ok(cs->cy == 0, "%d != 0\n", cs->cy);
1744 break;
1745 }
1746
1747 case WM_GETMINMAXINFO:
1748 {
1749 HWND parent = GetParent(hwnd);
1750 RECT rc;
1751 MINMAXINFO *minmax = (MINMAXINFO *)lparam;
1752 LONG style, exstyle;
1753
1754 style = GetWindowLongA(hwnd, GWL_STYLE);
1755 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
1756
1757 GetClientRect(parent, &rc);
1758 trace("WM_GETMINMAXINFO: parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
1759
1760 GetClientRect(parent, &rc);
1761 if ((style & WS_CAPTION) == WS_CAPTION)
1762 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
1763 AdjustWindowRectEx(&rc, style, 0, exstyle);
1764 dump_minmax_info( minmax );
1765
1766 ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n",
1767 minmax->ptMaxSize.x, rc.right - rc.left);
1768 ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %d != %d\n",
1769 minmax->ptMaxSize.y, rc.bottom - rc.top);
1770 break;
1771 }
1772
1773 case WM_WINDOWPOSCHANGED:
1774 {
1775 WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1776 RECT rc1, rc2;
1777
1778 GetWindowRect(hwnd, &rc1);
1779 SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
1780 /* note: winpos coordinates are relative to parent */
1781 MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
1782 ok(EqualRect(&rc1, &rc2), "rects do not match, window=(%d,%d)-(%d,%d) pos=(%d,%d)-(%d,%d)\n",
1783 rc1.left, rc1.top, rc1.right, rc1.bottom,
1784 rc2.left, rc2.top, rc2.right, rc2.bottom);
1785 GetWindowRect(hwnd, &rc1);
1786 GetClientRect(hwnd, &rc2);
1787 DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
1788 MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
1789 ok(EqualRect(&rc1, &rc2), "rects do not match, window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d)\n",
1790 rc1.left, rc1.top, rc1.right, rc1.bottom,
1791 rc2.left, rc2.top, rc2.right, rc2.bottom);
1792 }
1793 /* fall through */
1794 case WM_WINDOWPOSCHANGING:
1795 {
1796 WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1797 WINDOWPOS my_winpos = *winpos;
1798
1799 trace("%s: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1800 (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED",
1801 winpos->hwnd, winpos->hwndInsertAfter,
1802 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1803
1804 DefWindowProcA(hwnd, msg, wparam, lparam);
1805
1806 ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)),
1807 "DefWindowProc should not change WINDOWPOS: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1808 winpos->hwnd, winpos->hwndInsertAfter,
1809 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1810
1811 return 1;
1812 }
1813 }
1814 return DefWindowProcA(hwnd, msg, wparam, lparam);
1815 }
1816
1817 static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1818 {
1819 static HWND mdi_client;
1820
1821 switch (msg)
1822 {
1823 case WM_CREATE:
1824 {
1825 CLIENTCREATESTRUCT client_cs;
1826 RECT rc;
1827
1828 GetClientRect(hwnd, &rc);
1829
1830 client_cs.hWindowMenu = 0;
1831 client_cs.idFirstChild = 1;
1832
1833 /* MDIClient without MDIS_ALLCHILDSTYLES */
1834 mdi_client = CreateWindowExA(0, "mdiclient",
1835 NULL,
1836 WS_CHILD /*| WS_VISIBLE*/,
1837 /* tests depend on a not zero MDIClient size */
1838 0, 0, rc.right, rc.bottom,
1839 hwnd, 0, GetModuleHandle(0),
1840 &client_cs);
1841 assert(mdi_client);
1842 test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild);
1843 DestroyWindow(mdi_client);
1844
1845 /* MDIClient with MDIS_ALLCHILDSTYLES */
1846 mdi_client = CreateWindowExA(0, "mdiclient",
1847 NULL,
1848 WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/,
1849 /* tests depend on a not zero MDIClient size */
1850 0, 0, rc.right, rc.bottom,
1851 hwnd, 0, GetModuleHandle(0),
1852 &client_cs);
1853 assert(mdi_client);
1854 test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild);
1855 DestroyWindow(mdi_client);
1856
1857 /* Test child window stack management */
1858 mdi_client = CreateWindowExA(0, "mdiclient",
1859 NULL,
1860 WS_CHILD,
1861 0, 0, rc.right, rc.bottom,
1862 hwnd, 0, GetModuleHandle(0),
1863 &client_cs);
1864 assert(mdi_client);
1865 test_MDI_child_stack(mdi_client);
1866 DestroyWindow(mdi_client);
1867 break;
1868 }
1869
1870 case WM_WINDOWPOSCHANGED:
1871 {
1872 WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1873 RECT rc1, rc2;
1874
1875 GetWindowRect(hwnd, &rc1);
1876 trace("window: (%d,%d)-(%d,%d)\n", rc1.left, rc1.top, rc1.right, rc1.bottom);
1877 SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy);
1878 /* note: winpos coordinates are relative to parent */
1879 MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2);
1880 trace("pos: (%d,%d)-(%d,%d)\n", rc2.left, rc2.top, rc2.right, rc2.bottom);
1881 ok(EqualRect(&rc1, &rc2), "rects do not match\n");
1882
1883 GetWindowRect(hwnd, &rc1);
1884 GetClientRect(hwnd, &rc2);
1885 DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1);
1886 MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2);
1887 ok(EqualRect(&rc1, &rc2), "rects do not match\n");
1888 }
1889 /* fall through */
1890 case WM_WINDOWPOSCHANGING:
1891 {
1892 WINDOWPOS *winpos = (WINDOWPOS *)lparam;
1893 WINDOWPOS my_winpos = *winpos;
1894
1895 trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
1896 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1897 winpos->hwnd, winpos->hwndInsertAfter,
1898 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1899
1900 DefWindowProcA(hwnd, msg, wparam, lparam);
1901
1902 trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
1903 winpos->hwnd, winpos->hwndInsertAfter,
1904 winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
1905
1906 ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)),
1907 "DefWindowProc should not change WINDOWPOS values\n");
1908
1909 return 1;
1910 }
1911
1912 case WM_CLOSE:
1913 PostQuitMessage(0);
1914 break;
1915 }
1916 return DefFrameProcA(hwnd, mdi_client, msg, wparam, lparam);
1917 }
1918
1919 static BOOL mdi_RegisterWindowClasses(void)
1920 {
1921 WNDCLASSA cls;
1922
1923 cls.style = 0;
1924 cls.lpfnWndProc = mdi_main_wnd_procA;
1925 cls.cbClsExtra = 0;
1926 cls.cbWndExtra = 0;
1927 cls.hInstance = GetModuleHandleA(0);
1928 cls.hIcon = 0;
1929 cls.hCursor = LoadCursorA(0, IDC_ARROW);
1930 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1931 cls.lpszMenuName = NULL;
1932 cls.lpszClassName = "MDI_parent_Class";
1933 if(!RegisterClassA(&cls)) return FALSE;
1934
1935 cls.lpfnWndProc = mdi_child_wnd_proc_1;
1936 cls.lpszClassName = "MDI_child_Class_1";
1937 if(!RegisterClassA(&cls)) return FALSE;
1938
1939 cls.lpfnWndProc = mdi_child_wnd_proc_2;
1940 cls.lpszClassName = "MDI_child_Class_2";
1941 if(!RegisterClassA(&cls)) return FALSE;
1942
1943 return TRUE;
1944 }
1945
1946 static void test_mdi(void)
1947 {
1948 HWND mdi_hwndMain;
1949 /*MSG msg;*/
1950
1951 if (!mdi_RegisterWindowClasses()) assert(0);
1952
1953 mdi_hwndMain = CreateWindowExA(0, "MDI_parent_Class", "MDI parent window",
1954 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
1955 WS_MAXIMIZEBOX /*| WS_VISIBLE*/,
1956 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
1957 GetDesktopWindow(), 0,
1958 GetModuleHandle(0), NULL);
1959 assert(mdi_hwndMain);
1960 /*
1961 while(GetMessage(&msg, 0, 0, 0))
1962 {
1963 TranslateMessage(&msg);
1964 DispatchMessage(&msg);
1965 }
1966 */
1967 DestroyWindow(mdi_hwndMain);
1968 }
1969
1970 static void test_icons(void)
1971 {
1972 WNDCLASSEXA cls;
1973 HWND hwnd;
1974 HICON icon = LoadIconA(0, IDI_APPLICATION);
1975 HICON icon2 = LoadIconA(0, IDI_QUESTION);
1976 HICON small_icon = LoadImageA(0, IDI_APPLICATION, IMAGE_ICON,
1977 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED );
1978 HICON res;
1979
1980 cls.cbSize = sizeof(cls);
1981 cls.style = 0;
1982 cls.lpfnWndProc = DefWindowProcA;
1983 cls.cbClsExtra = 0;
1984 cls.cbWndExtra = 0;
1985 cls.hInstance = 0;
1986 cls.hIcon = LoadIconA(0, IDI_HAND);
1987 cls.hIconSm = small_icon;
1988 cls.hCursor = LoadCursorA(0, IDC_ARROW);
1989 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
1990 cls.lpszMenuName = NULL;
1991 cls.lpszClassName = "IconWindowClass";
1992
1993 RegisterClassExA(&cls);
1994
1995 hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0,
1996 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL);
1997 assert( hwnd );
1998
1999 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
2000 ok( res == 0, "wrong big icon %p/0\n", res );
2001 res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon );
2002 ok( res == 0, "wrong previous big icon %p/0\n", res );
2003 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
2004 ok( res == icon, "wrong big icon after set %p/%p\n", res, icon );
2005 res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 );
2006 ok( res == icon, "wrong previous big icon %p/%p\n", res, icon );
2007 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
2008 ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 );
2009
2010 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
2011 ok( res == 0, "wrong small icon %p/0\n", res );
2012 /* this test is XP specific */
2013 /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
2014 ok( res != 0, "wrong small icon %p\n", res );*/
2015 res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon );
2016 ok( res == 0, "wrong previous small icon %p/0\n", res );
2017 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
2018 ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );
2019 /* this test is XP specific */
2020 /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
2021 ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );*/
2022 res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon );
2023 ok( res == icon, "wrong previous small icon %p/%p\n", res, icon );
2024 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
2025 ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );
2026 /* this test is XP specific */
2027 /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
2028 ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );*/
2029
2030 /* make sure the big icon hasn't changed */
2031 res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
2032 ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 );
2033
2034 DestroyWindow( hwnd );
2035 }
2036
2037 static LRESULT WINAPI nccalcsize_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2038 {
2039 if (msg == WM_NCCALCSIZE)
2040 {
2041 RECT *rect = (RECT *)lparam;
2042 /* first time around increase the rectangle, next time decrease it */
2043 if (rect->left == 100) InflateRect( rect, 10, 10 );
2044 else InflateRect( rect, -10, -10 );
2045 return 0;
2046 }
2047 return DefWindowProc( hwnd, msg, wparam, lparam );
2048 }
2049
2050 static void test_SetWindowPos(HWND hwnd, HWND hwnd2)
2051 {
2052 RECT orig_win_rc, rect;
2053 LONG_PTR old_proc;
2054 HWND hwnd_grandchild, hwnd_child, hwnd_child2;
2055 HWND hwnd_desktop;
2056 RECT rc1, rc2;
2057 BOOL ret;
2058
2059 SetRect(&rect, 111, 222, 333, 444);
2060 ok(!GetWindowRect(0, &rect), "GetWindowRect succeeded\n");
2061 ok(rect.left == 111 && rect.top == 222 && rect.right == 333 && rect.bottom == 444,
2062 "wrong window rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
2063
2064 SetRect(&rect, 111, 222, 333, 444);
2065 ok(!GetClientRect(0, &rect), "GetClientRect succeeded\n");
2066 ok(rect.left == 111 && rect.top == 222 && rect.right == 333 && rect.bottom == 444,
2067 "wrong window rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
2068
2069 GetWindowRect(hwnd, &orig_win_rc);
2070
2071 old_proc = SetWindowLongPtr( hwnd, GWLP_WNDPROC, (ULONG_PTR)nccalcsize_proc );
2072 ret = SetWindowPos(hwnd, 0, 100, 100, 0, 0, SWP_NOZORDER|SWP_FRAMECHANGED);
2073 ok(ret, "Got %d\n", ret);
2074 GetWindowRect( hwnd, &rect );
2075 ok( rect.left == 100 && rect.top == 100 && rect.right == 100 && rect.bottom == 100,
2076 "invalid window rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
2077 GetClientRect( hwnd, &rect );
2078 MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 );
2079 ok( rect.left == 90 && rect.top == 90 && rect.right == 110 && rect.bottom == 110,
2080 "invalid client rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
2081
2082 ret = SetWindowPos(hwnd, 0, 200, 200, 0, 0, SWP_NOZORDER|SWP_FRAMECHANGED);
2083 ok(ret, "Got %d\n", ret);
2084 GetWindowRect( hwnd, &rect );
2085 ok( rect.left == 200 && rect.top == 200 && rect.right == 200 && rect.bottom == 200,
2086 "invalid window rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
2087 GetClientRect( hwnd, &rect );
2088 MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 );
2089 ok( rect.left == 210 && rect.top == 210 && rect.right == 190 && rect.bottom == 190,
2090 "invalid client rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
2091
2092 ret = SetWindowPos(hwnd, 0, orig_win_rc.left, orig_win_rc.top,
2093 orig_win_rc.right, orig_win_rc.bottom, 0);
2094 ok(ret, "Got %d\n", ret);
2095 SetWindowLongPtr( hwnd, GWLP_WNDPROC, old_proc );
2096
2097 /* Win9x truncates coordinates to 16-bit irrespectively */
2098 if (!is_win9x)
2099 {
2100 ret = SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOMOVE);
2101 ok(ret, "Got %d\n", ret);
2102 ret = SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOMOVE);
2103 ok(ret, "Got %d\n", ret);
2104
2105 ret = SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOSIZE);
2106 ok(ret, "Got %d\n", ret);
2107 ret = SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOSIZE);
2108 ok(ret, "Got %d\n", ret);
2109 }
2110
2111 ret = SetWindowPos(hwnd, 0, orig_win_rc.left, orig_win_rc.top,
2112 orig_win_rc.right, orig_win_rc.bottom, 0);
2113 ok(ret, "Got %d\n", ret);
2114
2115 ok(!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST), "WS_EX_TOPMOST should not be set\n");
2116 ret = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2117 ok(ret, "Got %d\n", ret);
2118 ok(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST, "WS_EX_TOPMOST should be set\n");
2119 ret = SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2120 ok(ret, "Got %d\n", ret);
2121 ok(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST, "WS_EX_TOPMOST should be set\n");
2122 ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2123 ok(ret, "Got %d\n", ret);
2124 ok(!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST), "WS_EX_TOPMOST should not be set\n");
2125
2126 hwnd_desktop = GetDesktopWindow();
2127 ok(!!hwnd_desktop, "Failed to get hwnd_desktop window (%d).\n", GetLastError());
2128 hwnd_child = create_tool_window(WS_VISIBLE|WS_CHILD, hwnd);
2129 ok(!!hwnd_child, "Failed to create child window (%d)\n", GetLastError());
2130 hwnd_grandchild = create_tool_window(WS_VISIBLE|WS_CHILD, hwnd_child);
2131 ok(!!hwnd_child, "Failed to create child window (%d)\n", GetLastError());
2132 hwnd_child2 = create_tool_window(WS_VISIBLE|WS_CHILD, hwnd);
2133 ok(!!hwnd_child2, "Failed to create second child window (%d)\n", GetLastError());
2134
2135 ret = SetWindowPos(hwnd, hwnd2, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2136 ok(ret, "Got %d\n", ret);
2137 check_active_state(hwnd, hwnd, hwnd);
2138
2139 ret = SetWindowPos(hwnd2, hwnd, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2140 ok(ret, "Got %d\n", ret);
2141 check_active_state(hwnd2, hwnd2, hwnd2);
2142
2143 /* Returns TRUE also for windows that are not siblings */
2144 ret = SetWindowPos(hwnd_child, hwnd2, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2145 ok(ret, "Got %d\n", ret);
2146 check_active_state(hwnd2, hwnd2, hwnd2);
2147
2148 ret = SetWindowPos(hwnd2, hwnd_child, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2149 ok(ret, "Got %d\n", ret);
2150 check_active_state(hwnd2, hwnd2, hwnd2);
2151
2152 /* Does not seem to do anything even without passing flags, still returns TRUE */
2153 GetWindowRect(hwnd_child, &rc1);
2154 ret = SetWindowPos(hwnd_child, hwnd2 , 1, 2, 3, 4, 0);
2155 ok(ret, "Got %d\n", ret);
2156 GetWindowRect(hwnd_child, &rc2);
2157 ok(rc1.left == rc2.left && rc1.top == rc2.top &&
2158 rc1.right == rc2.right && rc1.bottom == rc2.bottom,
2159 "(%d, %d, %d, %d) != (%d, %d, %d, %d)\n",
2160 rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom);
2161 check_active_state(hwnd2, hwnd2, hwnd2);
2162
2163 /* Same thing the other way around. */
2164 GetWindowRect(hwnd2, &rc1);
2165 ret = SetWindowPos(hwnd2, hwnd_child, 1, 2, 3, 4, 0);
2166 ok(ret, "Got %d\n", ret);
2167 GetWindowRect(hwnd2, &rc2);
2168 ok(rc1.left == rc2.left && rc1.top == rc2.top &&
2169 rc1.right == rc2.right && rc1.bottom == rc2.bottom,
2170 "(%d, %d, %d, %d) != (%d, %d, %d, %d)\n",
2171 rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom);
2172 check_active_state(hwnd2, hwnd2, hwnd2);
2173
2174 /* .. and with these windows. */
2175 GetWindowRect(hwnd_grandchild, &rc1);
2176 ret = SetWindowPos(hwnd_grandchild, hwnd_child2, 1, 2, 3, 4, 0);
2177 ok(ret, "Got %d\n", ret);
2178 GetWindowRect(hwnd_grandchild, &rc2);
2179 ok(rc1.left == rc2.left && rc1.top == rc2.top &&
2180 rc1.right == rc2.right && rc1.bottom == rc2.bottom,
2181 "(%d, %d, %d, %d) != (%d, %d, %d, %d)\n",
2182 rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom);
2183 check_active_state(hwnd2, hwnd2, hwnd2);
2184
2185 /* Add SWP_NOZORDER and it will be properly resized. */
2186 GetWindowRect(hwnd_grandchild, &rc1);
2187 ret = SetWindowPos(hwnd_grandchild, hwnd_child2, 1, 2, 3, 4, SWP_NOZORDER);
2188 ok(ret, "Got %d\n", ret);
2189 GetWindowRect(hwnd_grandchild, &rc2);
2190 ok((rc1.left+1) == rc2.left && (rc1.top+2) == rc2.top &&
2191 (rc1.left+4) == rc2.right && (rc1.top+6) == rc2.bottom,
2192 "(%d, %d, %d, %d) != (%d, %d, %d, %d)\n",
2193 rc1.left+1, rc1.top+2, rc1.left+4, rc1.top+6, rc2.left, rc2.top, rc2.right, rc2.bottom);
2194 check_active_state(hwnd2, hwnd2, hwnd2);
2195
2196 /* Given a sibling window, the window is properly resized. */
2197 GetWindowRect(hwnd_child, &rc1);
2198 ret = SetWindowPos(hwnd_child, hwnd_child2, 1, 2, 3, 4, 0);
2199 ok(ret, "Got %d\n", ret);
2200 GetWindowRect(hwnd_child, &rc2);
2201 ok((rc1.left+1) == rc2.left && (rc1.top+2) == rc2.top &&
2202 (rc1.left+4) == rc2.right && (rc1.top+6) == rc2.bottom,
2203 "(%d, %d, %d, %d) != (%d, %d, %d, %d)\n",
2204 rc1.left+1, rc1.top+2, rc1.left+4, rc1.top+6, rc2.left, rc2.top, rc2.right, rc2.bottom);
2205 check_active_state(hwnd2, hwnd2, hwnd2);
2206
2207 /* Involving the desktop window changes things. */
2208 ret = SetWindowPos(hwnd_child, hwnd_desktop, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2209 ok(!ret, "Got %d\n", ret);
2210 check_active_state(hwnd2, hwnd2, hwnd2);
2211
2212 GetWindowRect(hwnd_child, &rc1);
2213 ret = SetWindowPos(hwnd_child, hwnd_desktop, 0, 0, 0, 0, 0);
2214 ok(!ret, "Got %d\n", ret);
2215 GetWindowRect(hwnd_child, &rc2);
2216 ok(rc1.top == rc2.top && rc1.left == rc2.left &&
2217 rc1.bottom == rc2.bottom && rc1.right == rc2.right,
2218 "(%d, %d, %d, %d) != (%d, %d, %d, %d)\n",
2219 rc1.top, rc1.left, rc1.bottom, rc1.right, rc2.top, rc2.left, rc2.bottom, rc2.right);
2220 check_active_state(hwnd2, hwnd2, hwnd2);
2221
2222 ret = SetWindowPos(hwnd_desktop, hwnd_child, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2223 ok(!ret, "Got %d\n", ret);
2224 check_active_state(hwnd2, hwnd2, hwnd2);
2225
2226 ret = SetWindowPos(hwnd_desktop, hwnd, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2227 ok(!ret, "Got %d\n", ret);
2228 check_active_state(hwnd2, hwnd2, hwnd2);
2229
2230 ret = SetWindowPos(hwnd, hwnd_desktop, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2231 ok(!ret, "Got %d\n", ret);
2232 check_active_state(hwnd2, hwnd2, hwnd2);
2233
2234 DestroyWindow(hwnd_grandchild);
2235 DestroyWindow(hwnd_child);
2236 DestroyWindow(hwnd_child2);
2237
2238 hwnd_child = create_tool_window(WS_CHILD|WS_POPUP|WS_SYSMENU, hwnd2);
2239 ok(!!hwnd_child, "Failed to create child window (%d)\n", GetLastError());
2240 ret = SetWindowPos(hwnd_child, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_SHOWWINDOW);
2241 ok(ret, "Got %d\n", ret);
2242 flush_events( TRUE );
2243 todo_wine check_active_state(hwnd2, hwnd2, hwnd2);
2244 DestroyWindow(hwnd_child);
2245 }
2246
2247 static void test_SetMenu(HWND parent)
2248 {
2249 HWND child;
2250 HMENU hMenu, ret;
2251 BOOL retok;
2252 DWORD style;
2253
2254 hMenu = CreateMenu();
2255 assert(hMenu);
2256
2257 ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
2258 if (0)
2259 {
2260 /* fails on (at least) Wine, NT4, XP SP2 */
2261 test_nonclient_area(parent);
2262 }
2263 ret = GetMenu(parent);
2264 ok(ret == hMenu, "unexpected menu id %p\n", ret);
2265 /* test whether we can destroy a menu assigned to a window */
2266 retok = DestroyMenu(hMenu);
2267 ok( retok, "DestroyMenu error %d\n", GetLastError());
2268 retok = IsMenu(hMenu);
2269 ok(!retok || broken(retok) /* nt4 */, "menu handle should be not valid after DestroyMenu\n");
2270 ret = GetMenu(parent);
2271 /* This test fails on Win9x */
2272 if (!is_win9x)
2273 ok(ret == hMenu, "unexpected menu id %p\n", ret);
2274 ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
2275 test_nonclient_area(parent);
2276
2277 hMenu = CreateMenu();
2278 assert(hMenu);
2279
2280 /* parent */
2281 ret = GetMenu(parent);
2282 ok(ret == 0, "unexpected menu id %p\n", ret);
2283
2284 ok(!SetMenu(parent, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
2285 test_nonclient_area(parent);
2286 ret = GetMenu(parent);
2287 ok(ret == 0, "unexpected menu id %p\n", ret);
2288
2289 ok(SetMenu(parent, hMenu), "SetMenu on a top level window should not fail\n");
2290 if (0)
2291 {
2292 /* fails on (at least) Wine, NT4, XP SP2 */
2293 test_nonclient_area(parent);
2294 }
2295 ret = GetMenu(parent);
2296 ok(ret == hMenu, "unexpected menu id %p\n", ret);
2297
2298 ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n");
2299 test_nonclient_area(parent);
2300 ret = GetMenu(parent);
2301 ok(ret == 0, "unexpected menu id %p\n", ret);
2302
2303 /* child */
2304 child = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, parent, (HMENU)10, 0, NULL);
2305 assert(child);
2306
2307 ret = GetMenu(child);
2308 ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
2309
2310 ok(!SetMenu(child, (HMENU)20), "SetMenu with invalid menu handle should fail\n");
2311 test_nonclient_area(child);
2312 ret = GetMenu(child);
2313 ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
2314
2315 ok(!SetMenu(child, hMenu), "SetMenu on a child window should fail\n");
2316 test_nonclient_area(child);
2317 ret = GetMenu(child);
2318 ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
2319
2320 ok(!SetMenu(child, 0), "SetMenu(0) on a child window should fail\n");
2321 test_nonclient_area(child);
2322 ret = GetMenu(child);
2323 ok(ret == (HMENU)10, "unexpected menu id %p\n", ret);
2324
2325 style = GetWindowLong(child, GWL_STYLE);
2326 SetWindowLong(child, GWL_STYLE, style | WS_POPUP);
2327 ok(SetMenu(child, hMenu), "SetMenu on a popup child window should not fail\n");
2328 ok(SetMenu(child, 0), "SetMenu on a popup child window should not fail\n");
2329 SetWindowLong(child, GWL_STYLE, style);
2330
2331 SetWindowLong(child, GWL_STYLE, style | WS_OVERLAPPED);
2332 ok(!SetMenu(child, hMenu), "SetMenu on a overlapped child window should fail\n");
2333 SetWindowLong(child, GWL_STYLE, style);
2334
2335 DestroyWindow(child);
2336 DestroyMenu(hMenu);
2337 }
2338
2339 static void test_window_tree(HWND parent, const DWORD *style, const int *order, int total)
2340 {
2341 HWND child[5], hwnd;
2342 INT_PTR i;
2343
2344 assert(total <= 5);
2345
2346 hwnd = GetWindow(parent, GW_CHILD);
2347 ok(!hwnd, "have to start without children to perform the test\n");
2348
2349 for (i = 0; i < total; i++)
2350 {
2351 if (style[i] & DS_CONTROL)
2352 {
2353 child[i] = CreateWindowExA(0, MAKEINTATOM(32770), "", style[i] & ~WS_VISIBLE,
2354 0,0,0,0, parent, (HMENU)i, 0, NULL);
2355 if (style[i] & WS_VISIBLE)
2356 ShowWindow(child[i], SW_SHOW);
2357
2358 SetWindowPos(child[i], HWND_BOTTOM, 0,0,10,10, SWP_NOACTIVATE);
2359 }
2360 else
2361 child[i] = CreateWindowExA(0, "static", "", style[i], 0,0,10,10,
2362 parent, (HMENU)i, 0, NULL);
2363 trace("child[%ld] = %p\n", i, child[i]);
2364 ok(child[i] != 0, "CreateWindowEx failed to create child window\n");
2365 }
2366
2367 hwnd = GetWindow(parent, GW_CHILD);
2368 ok(hwnd != 0, "GetWindow(GW_CHILD) failed\n");
2369 ok(hwnd == GetWindow(child[total - 1], GW_HWNDFIRST), "GW_HWNDFIRST is wrong\n");
2370 ok(child[order[total - 1]] == GetWindow(child[0], GW_HWNDLAST), "GW_HWNDLAST is wrong\n");
2371
2372 for (i = 0; i < total; i++)
2373 {
2374 trace("hwnd[%ld] = %p\n", i, hwnd);
2375 ok(child[order[i]] == hwnd, "Z order of child #%ld is wrong\n", i);
2376
2377 hwnd = GetWindow(hwnd, GW_HWNDNEXT);
2378 }
2379
2380 for (i = 0; i < total; i++)
2381 ok(DestroyWindow(child[i]), "DestroyWindow failed\n");
2382 }
2383
2384 static void test_children_zorder(HWND parent)
2385 {
2386 const DWORD simple_style[5] = { WS_CHILD, WS_CHILD, WS_CHILD, WS_CHILD,
2387 WS_CHILD };
2388 const int simple_order[5] = { 0, 1, 2, 3, 4 };
2389
2390 const DWORD complex_style[5] = { WS_CHILD, WS_CHILD | WS_MAXIMIZE,
2391 WS_CHILD | WS_VISIBLE, WS_CHILD,
2392 WS_CHILD | WS_MAXIMIZE | WS_VISIBLE };
2393 const int complex_order_1[1] = { 0 };
2394 const int complex_order_2[2] = { 1, 0 };
2395 const int complex_order_3[3] = { 1, 0, 2 };
2396 const int complex_order_4[4] = { 1, 0, 2, 3 };
2397 const int complex_order_5[5] = { 4, 1, 0, 2, 3 };
2398 const DWORD complex_style_6[3] = { WS_CHILD | WS_VISIBLE,
2399 WS_CHILD | WS_CLIPSIBLINGS | DS_CONTROL | WS_VISIBLE,
2400 WS_CHILD | WS_VISIBLE };
2401 const int complex_order_6[3] = { 0, 1, 2 };
2402
2403 /* simple WS_CHILD */
2404 test_window_tree(parent, simple_style, simple_order, 5);
2405
2406 /* complex children styles */
2407 test_window_tree(parent, complex_style, complex_order_1, 1);
2408 test_window_tree(parent, complex_style, complex_order_2, 2);
2409 test_window_tree(parent, complex_style, complex_order_3, 3);
2410 test_window_tree(parent, complex_style, complex_order_4, 4);
2411 test_window_tree(parent, complex_style, complex_order_5, 5);
2412
2413 /* another set of complex children styles */
2414 test_window_tree(parent, complex_style_6, complex_order_6, 3);
2415 }
2416
2417 #define check_z_order(hwnd, next, prev, owner, topmost) \
2418 check_z_order_debug((hwnd), (next), (prev), (owner), (topmost), \
2419 __FILE__, __LINE__)
2420
2421 static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner,
2422 BOOL topmost, const char *file, int line)
2423 {
2424 HWND test;
2425 DWORD ex_style;
2426
2427 test = GetWindow(hwnd, GW_HWNDNEXT);
2428 /* skip foreign windows */
2429 while (test && test != next &&
2430 (GetWindowThreadProcessId(test, NULL) != our_pid ||
2431 UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0) ||
2432 GetWindow(test, GW_OWNER) == next))
2433 {
2434 /*trace("skipping next %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/
2435 test = GetWindow(test, GW_HWNDNEXT);
2436 }
2437 ok_(file, line)(next == test, "%p: expected next %p, got %p\n", hwnd, next, test);
2438
2439 test = GetWindow(hwnd, GW_HWNDPREV);
2440 /* skip foreign windows */
2441 while (test && test != prev &&
2442 (GetWindowThreadProcessId(test, NULL) != our_pid ||
2443 UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0) ||
2444 GetWindow(test, GW_OWNER) == hwnd))
2445 {
2446 /*trace("skipping prev %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/
2447 test = GetWindow(test, GW_HWNDPREV);
2448 }
2449 ok_(file, line)(prev == test, "%p: expected prev %p, got %p\n", hwnd, prev, test);
2450
2451 test = GetWindow(hwnd, GW_OWNER);
2452 ok_(file, line)(owner == test, "%p: expected owner %p, got %p\n", hwnd, owner, test);
2453
2454 ex_style = GetWindowLong(hwnd, GWL_EXSTYLE);
2455 ok_(file, line)(!(ex_style & WS_EX_TOPMOST) == !topmost, "%p: expected %stopmost\n",
2456 hwnd, topmost ? "" : "NOT ");
2457 }
2458
2459 static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style)
2460 {
2461 HWND hwnd_A, hwnd_B, hwnd_C, hwnd_F;
2462
2463 trace("hwnd_D %p, hwnd_E %p\n", hwnd_D, hwnd_E);
2464
2465 SetWindowPos(hwnd_E, hwnd_D, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2466
2467 check_z_order(hwnd_D, hwnd_E, 0, 0, FALSE);
2468 check_z_order(hwnd_E, 0, hwnd_D, 0, FALSE);
2469
2470 hwnd_F = CreateWindowEx(0, "MainWindowClass", "Owner window",
2471 WS_OVERLAPPED | WS_CAPTION,
2472 100, 100, 100, 100,
2473 0, 0, GetModuleHandle(0), NULL);
2474 trace("hwnd_F %p\n", hwnd_F);
2475 check_z_order(hwnd_F, hwnd_D, 0, 0, FALSE);
2476
2477 SetWindowPos(hwnd_F, hwnd_E, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2478 check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE);
2479 check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE);
2480 check_z_order(hwnd_D, hwnd_E, 0, 0, FALSE);
2481
2482 hwnd_C = CreateWindowEx(0, "MainWindowClass", NULL,
2483 style,
2484 100, 100, 100, 100,
2485 hwnd_F, 0, GetModuleHandle(0), NULL);
2486 trace("hwnd_C %p\n", hwnd_C);
2487 check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE);
2488 check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE);
2489 check_z_order(hwnd_D, hwnd_E, hwnd_C, 0, FALSE);
2490 check_z_order(hwnd_C, hwnd_D, 0, hwnd_F, FALSE);
2491
2492 hwnd_B = CreateWindowEx(WS_EX_TOPMOST, "MainWindowClass", NULL,
2493 style,
2494 100, 100, 100, 100,
2495 hwnd_F, 0, GetModuleHandle(0), NULL);
2496 trace("hwnd_B %p\n", hwnd_B);
2497 check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE);
2498 check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE);
2499 check_z_order(hwnd_D, hwnd_E, hwnd_C, 0, FALSE);
2500 check_z_order(hwnd_C, hwnd_D, hwnd_B, hwnd_F, FALSE);
2501 check_z_order(hwnd_B, hwnd_C, 0, hwnd_F, TRUE);
2502
2503 hwnd_A = CreateWindowEx(WS_EX_TOPMOST, "MainWindowClass", NULL,
2504 style,
2505 100, 100, 100, 100,
2506 0, 0, GetModuleHandle(0), NULL);
2507 trace("hwnd_A %p\n", hwnd_A);
2508 check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE);
2509 check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE);
2510 check_z_order(hwnd_D, hwnd_E, hwnd_C, 0, FALSE);
2511 check_z_order(hwnd_C, hwnd_D, hwnd_B, hwnd_F, FALSE);
2512 check_z_order(hwnd_B, hwnd_C, hwnd_A, hwnd_F, TRUE);
2513 check_z_order(hwnd_A, hwnd_B, 0, 0, TRUE);
2514
2515 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);
2516
2517 /* move hwnd_F and its popups up */
2518 SetWindowPos(hwnd_F, HWND_TOP, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2519 check_z_order(hwnd_E, 0, hwnd_D, 0, FALSE);
2520 check_z_order(hwnd_D, hwnd_E, hwnd_F, 0, FALSE);
2521 check_z_order(hwnd_F, hwnd_D, hwnd_C, 0, FALSE);
2522 check_z_order(hwnd_C, hwnd_F, hwnd_B, hwnd_F, FALSE);
2523 check_z_order(hwnd_B, hwnd_C, hwnd_A, hwnd_F, TRUE);
2524 check_z_order(hwnd_A, hwnd_B, 0, 0, TRUE);
2525
2526 /* move hwnd_F and its popups down */
2527 #if 0 /* enable once Wine is fixed to pass this test */
2528 SetWindowPos(hwnd_F, HWND_BOTTOM, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
2529 check_z_order(hwnd_F, 0, hwnd_C, 0, FALSE);
2530 check_z_order(hwnd_C, hwnd_F, hwnd_B, hwnd_F, FALSE);
2531 check_z_order(hwnd_B, hwnd_C, hwnd_E, hwnd_F, FALSE);
2532 check_z_order(hwnd_E, hwnd_B, hwnd_D, 0, FALSE);
2533 check_z_order(hwnd_D, hwnd_E, hwnd_A, 0, FALSE);
2534 check_z_order(hwnd_A, hwnd_D, 0, 0, TRUE);
2535 #endif
2536
2537 /* make hwnd_C owned by a topmost window */
2538 DestroyWindow( hwnd_C );
2539 hwnd_C = CreateWindowEx(0, "MainWindowClass", NULL,
2540 style,
2541 100, 100, 100, 100,
2542 hwnd_A, 0, GetModuleHandle(0), NULL);
2543 trace("hwnd_C %p\n", hwnd_C);
2544 check_z_order(hwnd_E, 0, hwnd_D, 0, FALSE);
2545 check_z_order(hwnd_D, hwnd_E, hwnd_F, 0, FALSE);
2546 check_z_order(hwnd_F, hwnd_D, hwnd_B, 0, FALSE);
2547 check_z_order(hwnd_B, hwnd_F, hwnd_A, hwnd_F, TRUE);
2548 check_z_order(hwnd_A, hwnd_B, hwnd_C, 0, TRUE);
2549 check_z_order(hwnd_C, hwnd_A, 0, hwnd_A, TRUE);
2550
2551 DestroyWindow(hwnd_A);
2552 DestroyWindow(hwnd_B);
2553 DestroyWindow(hwnd_C);
2554 DestroyWindow(hwnd_F);
2555 }
2556
2557 static void test_vis_rgn( HWND hwnd )
2558 {
2559 RECT win_rect, rgn_rect;
2560 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
2561 HDC hdc;
2562
2563 ShowWindow(hwnd,SW_SHOW);
2564 hdc = GetDC( hwnd );
2565 ok( GetRandomRgn( hdc, hrgn, SYSRGN ) != 0, "GetRandomRgn failed\n" );
2566 GetWindowRect( hwnd, &win_rect );
2567 GetRgnBox( hrgn, &rgn_rect );
2568 if (is_win9x)
2569 {
2570 trace("win9x, mapping to screen coords\n");
2571 MapWindowPoints( hwnd, 0, (POINT *)&rgn_rect, 2 );
2572 }
2573 trace("win: %d,%d-%d,%d\n", win_rect.left, win_rect.top, win_rect.right, win_rect.bottom );
2574 trace("rgn: %d,%d-%d,%d\n", rgn_rect.left, rgn_rect.top, rgn_rect.right, rgn_rect.bottom );
2575 ok( win_rect.left <= rgn_rect.left, "rgn left %d not inside win rect %d\n",
2576 rgn_rect.left, win_rect.left );
2577 ok( win_rect.top <= rgn_rect.top, "rgn top %d not inside win rect %d\n",
2578 rgn_rect.top, win_rect.top );
2579 ok( win_rect.right >= rgn_rect.right, "rgn right %d not inside win rect %d\n",
2580 rgn_rect.right, win_rect.right );
2581 ok( win_rect.bottom >= rgn_rect.bottom, "rgn bottom %d not inside win rect %d\n",
2582 rgn_rect.bottom, win_rect.bottom );
2583 ReleaseDC( hwnd, hdc );
2584 }
2585
2586 static LRESULT WINAPI set_focus_on_activate_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
2587 {
2588 if (msg == WM_ACTIVATE && LOWORD(wp) == WA_ACTIVE)
2589 {
2590 HWND child = GetWindow(hwnd, GW_CHILD);
2591 ok(child != 0, "couldn't find child window\n");
2592 SetFocus(child);
2593 ok(GetFocus() == child, "Focus should be on child %p\n", child);
2594 return 0;
2595 }
2596 return DefWindowProc(hwnd, msg, wp, lp);
2597 }
2598
2599 static void test_SetFocus(HWND hwnd)
2600 {
2601 HWND child, child2, ret;
2602 WNDPROC old_wnd_proc;
2603
2604 /* check if we can set focus to non-visible windows */
2605
2606 ShowWindow(hwnd, SW_SHOW);
2607 SetFocus(0);
2608 SetFocus(hwnd);
2609 ok( GetFocus() == hwnd, "Failed to set focus to visible window %p\n", hwnd );
2610 ok( GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE, "Window %p not visible\n", hwnd );
2611 ShowWindow(hwnd, SW_HIDE);
2612 SetFocus(0);
2613 SetFocus(hwnd);
2614 ok( GetFocus() == hwnd, "Failed to set focus to invisible window %p\n", hwnd );
2615 ok( !(GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE), "Window %p still visible\n", hwnd );
2616 child = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, hwnd, 0, 0, NULL);
2617 assert(child);
2618 SetFocus(child);
2619 ok( GetFocus() == child, "Failed to set focus to invisible child %p\n", child );
2620 ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
2621 ShowWindow(child, SW_SHOW);
2622 ok( GetWindowLong(child,GWL_STYLE) & WS_VISIBLE, "Child %p is not visible\n", child );
2623 ok( GetFocus() == child, "Focus no longer on child %p\n", child );
2624 ShowWindow(child, SW_HIDE);
2625 ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
2626 ok( GetFocus() == hwnd, "Focus should be on parent %p, not %p\n", hwnd, GetFocus() );
2627 ShowWindow(child, SW_SHOW);
2628 child2 = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, child, 0, 0, NULL);
2629 assert(child2);
2630 ShowWindow(child2, SW_SHOW);
2631 SetFocus(child2);
2632 ShowWindow(child, SW_HIDE);
2633 ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child );
2634 ok( GetFocus() == child2, "Focus should be on %p, not %p\n", child2, GetFocus() );
2635 ShowWindow(child, SW_SHOW);
2636 SetFocus(child);
2637 ok( GetFocus() == child, "Focus should be on child %p\n", child );
2638 SetWindowPos(child,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW);
2639 ok( GetFocus() == child, "Focus should still be on child %p\n", child );
2640
2641 ShowWindow(child, SW_HIDE);