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