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