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