2 * Unit tests for window stations and desktops
4 * Copyright 2002 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/test.h"
27 #define DESKTOP_ALL_ACCESS 0x01ff
29 static void print_object( HANDLE obj
)
34 strcpy( buffer
, "foobar" );
35 if (!GetUserObjectInformationA( obj
, UOI_NAME
, buffer
, sizeof(buffer
), &size
))
36 trace( "could not get info for %p\n", obj
);
38 trace( "obj %p name '%s'\n", obj
, buffer
);
39 strcpy( buffer
, "foobar" );
40 if (!GetUserObjectInformationA( obj
, UOI_TYPE
, buffer
, sizeof(buffer
), &size
))
41 trace( "could not get type for %p\n", obj
);
43 trace( "obj %p type '%s'\n", obj
, buffer
);
46 static void register_class(void)
50 cls
.style
= CS_DBLCLKS
;
51 cls
.lpfnWndProc
= DefWindowProcA
;
54 cls
.hInstance
= GetModuleHandleA(0);
56 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
57 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
58 cls
.lpszMenuName
= NULL
;
59 cls
.lpszClassName
= "WinStationClass";
63 static HDESK initial_desktop
;
65 static DWORD CALLBACK
thread( LPVOID arg
)
68 HWND hwnd
= CreateWindowExA(0,"WinStationClass","test",WS_POPUP
,0,0,100,100,GetDesktopWindow(),0,0,0);
69 ok( hwnd
!= 0, "CreateWindow failed\n" );
70 d1
= GetThreadDesktop(GetCurrentThreadId());
71 trace( "thread %p desktop: %p\n", arg
, d1
);
72 ok( d1
== initial_desktop
, "thread %p doesn't use initial desktop\n", arg
);
74 SetLastError( 0xdeadbeef );
75 ok( !CloseHandle( d1
), "CloseHandle succeeded\n" );
76 ok( GetLastError() == ERROR_INVALID_HANDLE
, "bad last error %d\n", GetLastError() );
77 SetLastError( 0xdeadbeef );
78 ok( !CloseDesktop( d1
), "CloseDesktop succeeded\n" );
79 ok( GetLastError() == ERROR_BUSY
|| broken(GetLastError() == 0xdeadbeef), /* wow64 */
80 "bad last error %d\n", GetLastError() );
82 d2
= CreateDesktop( "foobar2", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
83 trace( "created desktop %p\n", d2
);
84 ok( d2
!= 0, "CreateDesktop failed\n" );
86 SetLastError( 0xdeadbeef );
87 ok( !SetThreadDesktop( d2
), "set thread desktop succeeded with existing window\n" );
88 ok( GetLastError() == ERROR_BUSY
|| broken(GetLastError() == 0xdeadbeef), /* wow64 */
89 "bad last error %d\n", GetLastError() );
91 DestroyWindow( hwnd
);
92 ok( SetThreadDesktop( d2
), "set thread desktop failed\n" );
93 d1
= GetThreadDesktop(GetCurrentThreadId());
94 ok( d1
== d2
, "GetThreadDesktop did not return set desktop %p/%p\n", d1
, d2
);
98 HANDLE hthread
= CreateThread( NULL
, 0, thread
, (char *)arg
+ 1, 0, NULL
);
100 WaitForSingleObject( hthread
, INFINITE
);
101 CloseHandle( hthread
);
106 static void test_handles(void)
117 w1
= GetProcessWindowStation();
118 ok( GetProcessWindowStation() == w1
, "GetProcessWindowStation returned different handles\n" );
119 ok( !CloseWindowStation(w1
), "closing process win station succeeded\n" );
120 SetLastError( 0xdeadbeef );
121 ok( !CloseHandle(w1
), "closing process win station handle succeeded\n" );
122 ok( GetLastError() == ERROR_INVALID_HANDLE
, "bad last error %d\n", GetLastError() );
126 ok( GetHandleInformation( w1
, &flags
), "GetHandleInformation failed\n" );
127 ok( !(flags
& HANDLE_FLAG_PROTECT_FROM_CLOSE
) ||
128 broken(flags
& HANDLE_FLAG_PROTECT_FROM_CLOSE
), /* set on nt4 */
129 "handle %p PROTECT_FROM_CLOSE set\n", w1
);
131 ok( DuplicateHandle( GetCurrentProcess(), w1
, GetCurrentProcess(), (PHANDLE
)&w2
, 0,
132 TRUE
, DUPLICATE_SAME_ACCESS
), "DuplicateHandle failed\n" );
133 ok( CloseWindowStation(w2
), "closing dup win station failed\n" );
135 ok( DuplicateHandle( GetCurrentProcess(), w1
, GetCurrentProcess(), (PHANDLE
)&w2
, 0,
136 TRUE
, DUPLICATE_SAME_ACCESS
), "DuplicateHandle failed\n" );
137 ok( CloseHandle(w2
), "closing dup win station handle failed\n" );
139 w2
= CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS
, NULL
);
141 ok( w2
!= 0 || le
== ERROR_ACCESS_DENIED
, "CreateWindowStation failed (%u)\n", le
);
144 ok( w2
!= w1
, "CreateWindowStation returned default handle\n" );
145 SetLastError( 0xdeadbeef );
146 ok( !CloseDesktop( (HDESK
)w2
), "CloseDesktop succeeded on win station\n" );
147 ok( GetLastError() == ERROR_INVALID_HANDLE
|| broken(GetLastError() == 0xdeadbeef), /* wow64 */
148 "bad last error %d\n", GetLastError() );
149 ok( CloseWindowStation( w2
), "CloseWindowStation failed\n" );
151 w2
= CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS
, NULL
);
152 ok( CloseHandle( w2
), "CloseHandle failed\n" );
154 else if (le
== ERROR_ACCESS_DENIED
)
155 win_skip( "Not enough privileges for CreateWindowStation\n" );
157 w2
= OpenWindowStation("winsta0", TRUE
, WINSTA_ALL_ACCESS
);
158 ok( w2
!= 0, "OpenWindowStation failed\n" );
159 ok( w2
!= w1
, "OpenWindowStation returned default handle\n" );
160 ok( CloseWindowStation( w2
), "CloseWindowStation failed\n" );
162 w2
= OpenWindowStation("dummy name", TRUE
, WINSTA_ALL_ACCESS
);
163 ok( !w2
, "open dummy win station succeeded\n" );
165 CreateMutexA( NULL
, 0, "foobar" );
166 w2
= CreateWindowStation("foobar", 0, WINSTA_ALL_ACCESS
, NULL
);
168 ok( w2
!= 0 || le
== ERROR_ACCESS_DENIED
, "create foobar station failed (%u)\n", le
);
172 w3
= OpenWindowStation("foobar", TRUE
, WINSTA_ALL_ACCESS
);
173 ok( w3
!= 0, "open foobar station failed\n" );
174 ok( w3
!= w2
, "open foobar station returned same handle\n" );
175 ok( CloseWindowStation( w2
), "CloseWindowStation failed\n" );
176 ok( CloseWindowStation( w3
), "CloseWindowStation failed\n" );
178 w3
= OpenWindowStation("foobar", TRUE
, WINSTA_ALL_ACCESS
);
179 ok( !w3
, "open foobar station succeeded\n" );
181 w2
= CreateWindowStation("foobar1", 0, WINSTA_ALL_ACCESS
, NULL
);
182 ok( w2
!= 0, "create foobar station failed\n" );
183 w3
= CreateWindowStation("foobar2", 0, WINSTA_ALL_ACCESS
, NULL
);
184 ok( w3
!= 0, "create foobar station failed\n" );
185 ok( GetHandleInformation( w2
, &flags
), "GetHandleInformation failed\n" );
186 ok( GetHandleInformation( w3
, &flags
), "GetHandleInformation failed\n" );
188 SetProcessWindowStation( w2
);
189 atom
= GlobalAddAtomA("foo");
190 ok( GlobalGetAtomNameA( atom
, buffer
, sizeof(buffer
) ) == 3, "GlobalGetAtomName failed\n" );
191 ok( !lstrcmpiA( buffer
, "foo" ), "bad atom value %s\n", buffer
);
193 ok( !CloseWindowStation( w2
), "CloseWindowStation succeeded\n" );
194 ok( GetHandleInformation( w2
, &flags
), "GetHandleInformation failed\n" );
196 SetProcessWindowStation( w3
);
197 ok( GetHandleInformation( w2
, &flags
), "GetHandleInformation failed\n" );
198 ok( CloseWindowStation( w2
), "CloseWindowStation failed\n" );
199 ok( GlobalGetAtomNameA( atom
, buffer
, sizeof(buffer
) ) == 3, "GlobalGetAtomName failed\n" );
200 ok( !lstrcmpiA( buffer
, "foo" ), "bad atom value %s\n", buffer
);
202 else if (le
== ERROR_ACCESS_DENIED
)
203 win_skip( "Not enough privileges for CreateWindowStation\n" );
206 d1
= GetThreadDesktop(GetCurrentThreadId());
207 initial_desktop
= d1
;
208 ok( GetThreadDesktop(GetCurrentThreadId()) == d1
,
209 "GetThreadDesktop returned different handles\n" );
212 ok( GetHandleInformation( d1
, &flags
), "GetHandleInformation failed\n" );
213 ok( !(flags
& HANDLE_FLAG_PROTECT_FROM_CLOSE
), "handle %p PROTECT_FROM_CLOSE set\n", d1
);
215 SetLastError( 0xdeadbeef );
216 ok( !CloseDesktop(d1
), "closing thread desktop succeeded\n" );
217 ok( GetLastError() == ERROR_BUSY
|| broken(GetLastError() == 0xdeadbeef), /* wow64 */
218 "bad last error %d\n", GetLastError() );
220 SetLastError( 0xdeadbeef );
221 if (CloseHandle( d1
)) /* succeeds on nt4 */
223 win_skip( "NT4 desktop handle management is completely different\n" );
226 ok( GetLastError() == ERROR_INVALID_HANDLE
, "bad last error %d\n", GetLastError() );
228 ok( DuplicateHandle( GetCurrentProcess(), d1
, GetCurrentProcess(), (PHANDLE
)&d2
, 0,
229 TRUE
, DUPLICATE_SAME_ACCESS
), "DuplicateHandle failed\n" );
230 ok( CloseDesktop(d2
), "closing dup desktop failed\n" );
232 ok( DuplicateHandle( GetCurrentProcess(), d1
, GetCurrentProcess(), (PHANDLE
)&d2
, 0,
233 TRUE
, DUPLICATE_SAME_ACCESS
), "DuplicateHandle failed\n" );
234 ok( CloseHandle(d2
), "closing dup desktop handle failed\n" );
236 d2
= OpenDesktop( "dummy name", 0, TRUE
, DESKTOP_ALL_ACCESS
);
237 ok( !d2
, "open dummy desktop succeeded\n" );
239 d2
= CreateDesktop( "foobar", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
240 ok( d2
!= 0, "create foobar desktop failed\n" );
241 SetLastError( 0xdeadbeef );
242 ok( !CloseWindowStation( (HWINSTA
)d2
), "CloseWindowStation succeeded on desktop\n" );
243 ok( GetLastError() == ERROR_INVALID_HANDLE
|| broken(GetLastError() == 0xdeadbeef), /* wow64 */
244 "bad last error %d\n", GetLastError() );
246 SetLastError( 0xdeadbeef );
247 d3
= CreateDesktop( "foobar", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
248 ok( d3
!= 0, "create foobar desktop again failed\n" );
249 ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() );
250 ok( CloseDesktop( d3
), "CloseDesktop failed\n" );
252 d3
= OpenDesktop( "foobar", 0, TRUE
, DESKTOP_ALL_ACCESS
);
253 ok( d3
!= 0, "open foobar desktop failed\n" );
254 ok( d3
!= d2
, "open foobar desktop returned same handle\n" );
255 ok( CloseDesktop( d2
), "CloseDesktop failed\n" );
256 ok( CloseDesktop( d3
), "CloseDesktop failed\n" );
258 d3
= OpenDesktop( "foobar", 0, TRUE
, DESKTOP_ALL_ACCESS
);
259 ok( !d3
, "open foobar desktop succeeded\n" );
261 ok( !CloseHandle(d1
), "closing thread desktop handle succeeded\n" );
262 d2
= GetThreadDesktop(GetCurrentThreadId());
263 ok( d1
== d2
, "got different handles after close\n" );
266 trace( "thread 1 desktop: %p\n", d1
);
268 hthread
= CreateThread( NULL
, 0, thread
, (LPVOID
)2, 0, &id
);
270 trace( "get other thread desktop: %p\n", GetThreadDesktop(id
) );
271 WaitForSingleObject( hthread
, INFINITE
);
272 CloseHandle( hthread
);
275 /* Enumeration tests */
277 static BOOL CALLBACK
window_station_callbackA(LPSTR winsta
, LPARAM lp
)
279 trace("window_station_callbackA called with argument %s\n", winsta
);
283 static BOOL CALLBACK
open_window_station_callbackA(LPSTR winsta
, LPARAM lp
)
287 trace("open_window_station_callbackA called with argument %s\n", winsta
);
288 hwinsta
= OpenWindowStationA(winsta
, FALSE
, WINSTA_ENUMERATE
);
289 ok(hwinsta
!= NULL
, "Could not open desktop %s!\n", winsta
);
291 CloseWindowStation(hwinsta
);
295 static void test_enumstations(void)
299 if (0) /* Crashes instead */
301 SetLastError(0xbabefeed);
302 ret
= EnumWindowStationsA(NULL
, 0);
303 ok(!ret
, "EnumWindowStationsA returned successfully!\n");
304 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "LastError is set to %08x\n", GetLastError());
307 SetLastError(0xdeadbeef);
308 ret
= EnumWindowStationsA(open_window_station_callbackA
, 0x12345);
309 ok(ret
== 0x12345, "EnumWindowStationsA returned %x\n", ret
);
310 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
312 SetLastError(0xdeadbeef);
313 ret
= EnumWindowStationsA(window_station_callbackA
, 0);
314 ok(!ret
, "EnumWindowStationsA returned %x\n", ret
);
315 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
318 static BOOL CALLBACK
desktop_callbackA(LPSTR desktop
, LPARAM lp
)
320 trace("desktop_callbackA called with argument %s\n", desktop
);
324 static BOOL CALLBACK
open_desktop_callbackA(LPSTR desktop
, LPARAM lp
)
329 trace("open_desktop_callbackA called with argument %s\n", desktop
);
330 /* Only try to open one desktop */
334 hdesk
= OpenDesktopA(desktop
, 0, FALSE
, DESKTOP_ENUMERATE
);
335 ok(hdesk
!= NULL
, "Could not open desktop %s!\n", desktop
);
341 static void test_enumdesktops(void)
345 if (0) /* Crashes instead */
347 SetLastError(0xbabefeed);
348 ret
= EnumDesktopsA(GetProcessWindowStation(), NULL
, 0);
349 ok(!ret
, "EnumDesktopsA returned successfully!\n");
350 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "LastError is set to %08x\n", GetLastError());
353 SetLastError(0xdeadbeef);
354 ret
= EnumDesktopsA(NULL
, desktop_callbackA
, 0x12345);
355 ok(ret
== 0x12345, "EnumDesktopsA returned %x\n", ret
);
356 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
358 SetLastError(0xdeadbeef);
359 ret
= EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA
, 0x12345);
360 ok(ret
== 0x12345, "EnumDesktopsA returned %x\n", ret
);
361 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
363 SetLastError(0xdeadbeef);
364 ret
= EnumDesktopsA(INVALID_HANDLE_VALUE
, desktop_callbackA
, 0x12345);
365 ok(!ret
, "EnumDesktopsA returned %x\n", ret
);
366 ok(GetLastError() == ERROR_INVALID_HANDLE
, "LastError is set to %08x\n", GetLastError());
368 SetLastError(0xdeadbeef);
369 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
370 ok(!ret
, "EnumDesktopsA returned %x\n", ret
);
371 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
374 /* Miscellaneous tests */
376 static void test_getuserobjectinformation(void)
381 WCHAR foobarTestW
[] = {'f','o','o','b','a','r','T','e','s','t',0};
382 WCHAR DesktopW
[] = {'D','e','s','k','t','o','p',0};
386 desk
= CreateDesktop("foobarTest", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
387 ok(desk
!= 0, "open foobarTest desktop failed\n");
389 strcpy(buffer
, "blahblah");
391 /** Tests for UOI_NAME **/
393 /* Get size, test size and return value/error code */
394 SetLastError(0xdeadbeef);
396 ret
= GetUserObjectInformationA(desk
, UOI_NAME
, NULL
, 0, &size
);
398 ok(!ret
, "GetUserObjectInformationA returned %x\n", ret
);
399 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
400 ok(size
== 22, "size is set to %d\n", size
); /* Windows returns Unicode length (11*2) */
403 SetLastError(0xdeadbeef);
405 ret
= GetUserObjectInformationA(desk
, UOI_NAME
, buffer
, sizeof(buffer
), &size
);
407 ok(ret
, "GetUserObjectInformationA returned %x\n", ret
);
408 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
410 ok(strcmp(buffer
, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer
);
411 ok(size
== 11, "size is set to %d\n", size
); /* 11 bytes in 'foobarTest\0' */
413 /* Get size, test size and return value/error code (Unicode) */
414 SetLastError(0xdeadbeef);
416 ret
= GetUserObjectInformationW(desk
, UOI_NAME
, NULL
, 0, &size
);
418 ok(!ret
, "GetUserObjectInformationW returned %x\n", ret
);
419 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
420 ok(size
== 22, "size is set to %d\n", size
); /* 22 bytes in 'foobarTest\0' in Unicode */
422 /* Get string (Unicode) */
423 SetLastError(0xdeadbeef);
425 ret
= GetUserObjectInformationW(desk
, UOI_NAME
, bufferW
, sizeof(bufferW
), &size
);
427 ok(ret
, "GetUserObjectInformationW returned %x\n", ret
);
428 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
430 ok(lstrcmpW(bufferW
, foobarTestW
) == 0, "Buffer is not set to 'foobarTest'\n");
431 ok(size
== 22, "size is set to %d\n", size
); /* 22 bytes in 'foobarTest\0' in Unicode */
433 /** Tests for UOI_TYPE **/
435 /* Get size, test size and return value/error code */
436 SetLastError(0xdeadbeef);
438 ret
= GetUserObjectInformationA(desk
, UOI_TYPE
, NULL
, 0, &size
);
440 ok(!ret
, "GetUserObjectInformationA returned %x\n", ret
);
441 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
442 ok(size
== 16, "size is set to %d\n", size
); /* Windows returns Unicode length (8*2) */
445 SetLastError(0xdeadbeef);
447 ret
= GetUserObjectInformationA(desk
, UOI_TYPE
, buffer
, sizeof(buffer
), &size
);
449 ok(ret
, "GetUserObjectInformationA returned %x\n", ret
);
450 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
452 ok(strcmp(buffer
, "Desktop") == 0, "Buffer is set to '%s'\n", buffer
);
453 ok(size
== 8, "size is set to %d\n", size
); /* 8 bytes in 'Desktop\0' */
455 /* Get size, test size and return value/error code (Unicode) */
457 SetLastError(0xdeadbeef);
458 ret
= GetUserObjectInformationW(desk
, UOI_TYPE
, NULL
, 0, &size
);
460 ok(!ret
, "GetUserObjectInformationW returned %x\n", ret
);
461 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
462 ok(size
== 16, "size is set to %d\n", size
); /* 16 bytes in 'Desktop\0' in Unicode */
464 /* Get string (Unicode) */
465 SetLastError(0xdeadbeef);
467 ret
= GetUserObjectInformationW(desk
, UOI_TYPE
, bufferW
, sizeof(bufferW
), &size
);
469 ok(ret
, "GetUserObjectInformationW returned %x\n", ret
);
470 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
472 ok(lstrcmpW(bufferW
, DesktopW
) == 0, "Buffer is not set to 'Desktop'\n");
473 ok(size
== 16, "size is set to %d\n", size
); /* 16 bytes in 'Desktop\0' in Unicode */
475 ok(CloseDesktop(desk
), "CloseDesktop failed\n");
478 START_TEST(winstation
)
480 /* Check whether this platform supports WindowStation calls */
482 SetLastError( 0xdeadbeef );
483 GetProcessWindowStation();
484 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
486 skip("WindowStation calls not supported on this platform\n");
493 test_getuserobjectinformation();