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
);
274 /* clean side effect */
275 SetProcessWindowStation( w1
);
278 /* Enumeration tests */
280 static BOOL CALLBACK
window_station_callbackA(LPSTR winsta
, LPARAM lp
)
282 trace("window_station_callbackA called with argument %s\n", winsta
);
286 static BOOL CALLBACK
open_window_station_callbackA(LPSTR winsta
, LPARAM lp
)
290 trace("open_window_station_callbackA called with argument %s\n", winsta
);
291 hwinsta
= OpenWindowStationA(winsta
, FALSE
, WINSTA_ENUMERATE
);
292 ok(hwinsta
!= NULL
, "Could not open desktop %s!\n", winsta
);
294 CloseWindowStation(hwinsta
);
298 static void test_enumstations(void)
302 if (0) /* Crashes instead */
304 SetLastError(0xbabefeed);
305 ret
= EnumWindowStationsA(NULL
, 0);
306 ok(!ret
, "EnumWindowStationsA returned successfully!\n");
307 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "LastError is set to %08x\n", GetLastError());
310 SetLastError(0xdeadbeef);
311 ret
= EnumWindowStationsA(open_window_station_callbackA
, 0x12345);
312 ok(ret
== 0x12345, "EnumWindowStationsA returned %x\n", ret
);
313 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
315 SetLastError(0xdeadbeef);
316 ret
= EnumWindowStationsA(window_station_callbackA
, 0);
317 ok(!ret
, "EnumWindowStationsA returned %x\n", ret
);
318 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
321 static BOOL CALLBACK
desktop_callbackA(LPSTR desktop
, LPARAM lp
)
323 trace("desktop_callbackA called with argument %s\n", desktop
);
327 static BOOL CALLBACK
open_desktop_callbackA(LPSTR desktop
, LPARAM lp
)
332 trace("open_desktop_callbackA called with argument %s\n", desktop
);
333 /* Only try to open one desktop */
337 hdesk
= OpenDesktopA(desktop
, 0, FALSE
, DESKTOP_ENUMERATE
);
338 ok(hdesk
!= NULL
, "Could not open desktop %s!\n", desktop
);
344 static void test_enumdesktops(void)
348 if (0) /* Crashes instead */
350 SetLastError(0xbabefeed);
351 ret
= EnumDesktopsA(GetProcessWindowStation(), NULL
, 0);
352 ok(!ret
, "EnumDesktopsA returned successfully!\n");
353 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "LastError is set to %08x\n", GetLastError());
356 SetLastError(0xdeadbeef);
357 ret
= EnumDesktopsA(NULL
, desktop_callbackA
, 0x12345);
358 ok(ret
== 0x12345, "EnumDesktopsA returned %x\n", ret
);
359 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
361 SetLastError(0xdeadbeef);
362 ret
= EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA
, 0x12345);
363 ok(ret
== 0x12345, "EnumDesktopsA returned %x\n", ret
);
364 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
366 SetLastError(0xdeadbeef);
367 ret
= EnumDesktopsA(INVALID_HANDLE_VALUE
, desktop_callbackA
, 0x12345);
368 ok(!ret
, "EnumDesktopsA returned %x\n", ret
);
369 ok(GetLastError() == ERROR_INVALID_HANDLE
, "LastError is set to %08x\n", GetLastError());
371 SetLastError(0xdeadbeef);
372 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
373 ok(!ret
, "EnumDesktopsA returned %x\n", ret
);
374 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
377 /* Miscellaneous tests */
379 static void test_getuserobjectinformation(void)
384 WCHAR foobarTestW
[] = {'f','o','o','b','a','r','T','e','s','t',0};
385 WCHAR DesktopW
[] = {'D','e','s','k','t','o','p',0};
389 desk
= CreateDesktop("foobarTest", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
390 ok(desk
!= 0, "open foobarTest desktop failed\n");
392 strcpy(buffer
, "blahblah");
394 /** Tests for UOI_NAME **/
396 /* Get size, test size and return value/error code */
397 SetLastError(0xdeadbeef);
399 ret
= GetUserObjectInformationA(desk
, UOI_NAME
, NULL
, 0, &size
);
401 ok(!ret
, "GetUserObjectInformationA returned %x\n", ret
);
402 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
403 ok(size
== 22, "size is set to %d\n", size
); /* Windows returns Unicode length (11*2) */
406 SetLastError(0xdeadbeef);
408 ret
= GetUserObjectInformationA(desk
, UOI_NAME
, buffer
, sizeof(buffer
), &size
);
410 ok(ret
, "GetUserObjectInformationA returned %x\n", ret
);
411 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
413 ok(strcmp(buffer
, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer
);
414 ok(size
== 11, "size is set to %d\n", size
); /* 11 bytes in 'foobarTest\0' */
416 /* Get size, test size and return value/error code (Unicode) */
417 SetLastError(0xdeadbeef);
419 ret
= GetUserObjectInformationW(desk
, UOI_NAME
, NULL
, 0, &size
);
421 ok(!ret
, "GetUserObjectInformationW returned %x\n", ret
);
422 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
423 ok(size
== 22, "size is set to %d\n", size
); /* 22 bytes in 'foobarTest\0' in Unicode */
425 /* Get string (Unicode) */
426 SetLastError(0xdeadbeef);
428 ret
= GetUserObjectInformationW(desk
, UOI_NAME
, bufferW
, sizeof(bufferW
), &size
);
430 ok(ret
, "GetUserObjectInformationW returned %x\n", ret
);
431 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
433 ok(lstrcmpW(bufferW
, foobarTestW
) == 0, "Buffer is not set to 'foobarTest'\n");
434 ok(size
== 22, "size is set to %d\n", size
); /* 22 bytes in 'foobarTest\0' in Unicode */
436 /** Tests for UOI_TYPE **/
438 /* Get size, test size and return value/error code */
439 SetLastError(0xdeadbeef);
441 ret
= GetUserObjectInformationA(desk
, UOI_TYPE
, NULL
, 0, &size
);
443 ok(!ret
, "GetUserObjectInformationA returned %x\n", ret
);
444 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
445 ok(size
== 16, "size is set to %d\n", size
); /* Windows returns Unicode length (8*2) */
448 SetLastError(0xdeadbeef);
450 ret
= GetUserObjectInformationA(desk
, UOI_TYPE
, buffer
, sizeof(buffer
), &size
);
452 ok(ret
, "GetUserObjectInformationA returned %x\n", ret
);
453 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
455 ok(strcmp(buffer
, "Desktop") == 0, "Buffer is set to '%s'\n", buffer
);
456 ok(size
== 8, "size is set to %d\n", size
); /* 8 bytes in 'Desktop\0' */
458 /* Get size, test size and return value/error code (Unicode) */
460 SetLastError(0xdeadbeef);
461 ret
= GetUserObjectInformationW(desk
, UOI_TYPE
, NULL
, 0, &size
);
463 ok(!ret
, "GetUserObjectInformationW returned %x\n", ret
);
464 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
465 ok(size
== 16, "size is set to %d\n", size
); /* 16 bytes in 'Desktop\0' in Unicode */
467 /* Get string (Unicode) */
468 SetLastError(0xdeadbeef);
470 ret
= GetUserObjectInformationW(desk
, UOI_TYPE
, bufferW
, sizeof(bufferW
), &size
);
472 ok(ret
, "GetUserObjectInformationW returned %x\n", ret
);
473 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
475 ok(lstrcmpW(bufferW
, DesktopW
) == 0, "Buffer is not set to 'Desktop'\n");
476 ok(size
== 16, "size is set to %d\n", size
); /* 16 bytes in 'Desktop\0' in Unicode */
478 ok(CloseDesktop(desk
), "CloseDesktop failed\n");
481 static void test_inputdesktop(void)
483 HDESK input_desk
, old_input_desk
, thread_desk
, old_thread_desk
, new_desk
;
488 inputs
[0].type
= INPUT_KEYBOARD
;
489 U(inputs
[0]).ki
.wVk
= 0;
490 U(inputs
[0]).ki
.wScan
= 0x3c0;
491 U(inputs
[0]).ki
.dwFlags
= KEYEVENTF_UNICODE
;
493 /* OpenInputDesktop creates new handles for each calls */
494 old_input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
496 ok(old_input_desk
!= NULL
, "OpenInputDesktop failed!\n");
497 memset(name
, 0, sizeof(name
));
498 ret
= GetUserObjectInformationA(old_input_desk
, UOI_NAME
, name
, 1024, NULL
);
500 ok(ret
, "GetUserObjectInformation failed!\n");
502 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
504 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
506 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
507 memset(name
, 0, sizeof(name
));
508 ret
= GetUserObjectInformationA(input_desk
, UOI_NAME
, name
, 1024, NULL
);
510 ok(ret
, "GetUserObjectInformation failed!\n");
512 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
515 ok(old_input_desk
!= input_desk
, "returned the same handle!\n");
516 ret
= CloseDesktop(input_desk
);
518 ok(ret
, "CloseDesktop failed!\n");
520 /* by default, GetThreadDesktop is the input desktop, SendInput should success. */
521 old_thread_desk
= GetThreadDesktop(GetCurrentThreadId());
522 ok(old_thread_desk
!= NULL
, "GetThreadDesktop faile!\n");
523 memset(name
, 0, sizeof(name
));
524 ret
= GetUserObjectInformationA(old_thread_desk
, UOI_NAME
, name
, 1024, NULL
);
525 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
527 SetLastError(0xdeadbeef);
528 ret
= SendInput(1, inputs
, sizeof(INPUT
));
529 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
530 ok(ret
== 1, "unexpected return count %d\n", ret
);
532 /* Set thread desktop to the new desktop, SendInput should fail. */
533 new_desk
= CreateDesktopA("new_desk", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
534 ok(new_desk
!= NULL
, "CreateDesktop failed!\n");
535 ret
= SetThreadDesktop(new_desk
);
536 ok(ret
, "SetThreadDesktop failed!\n");
537 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
538 ok(thread_desk
== new_desk
, "thread desktop doesn't match!\n");
539 memset(name
, 0, sizeof(name
));
540 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
541 ok(!strcmp(name
, "new_desk"), "unexpected desktop %s\n", name
);
543 SetLastError(0xdeadbeef);
544 ret
= SendInput(1, inputs
, sizeof(INPUT
));
546 ok(GetLastError() == ERROR_ACCESS_DENIED
, "unexpected last error %08x\n", GetLastError());
547 ok(ret
== 1 || broken(ret
== 0) /* Win64 */, "unexpected return count %d\n", ret
);
549 /* Set thread desktop back to the old thread desktop, SendInput should success. */
550 ret
= SetThreadDesktop(old_thread_desk
);
551 ok(ret
, "SetThreadDesktop failed!\n");
552 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
553 ok(thread_desk
== old_thread_desk
, "thread desktop doesn't match!\n");
554 memset(name
, 0, sizeof(name
));
555 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
556 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
558 SetLastError(0xdeadbeef);
559 ret
= SendInput(1, inputs
, sizeof(INPUT
));
560 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
561 ok(ret
== 1, "unexpected return count %d\n", ret
);
563 /* Set thread desktop to the input desktop, SendInput should success. */
564 ret
= SetThreadDesktop(old_input_desk
);
566 ok(ret
, "SetThreadDesktop failed!\n");
567 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
569 ok(thread_desk
== old_input_desk
, "thread desktop doesn't match!\n");
570 memset(name
, 0, sizeof(name
));
571 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
572 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
574 SetLastError(0xdeadbeef);
575 ret
= SendInput(1, inputs
, sizeof(INPUT
));
576 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
577 ok(ret
== 1, "unexpected return count %d\n", ret
);
579 /* Switch input desktop to the new desktop, SendInput should fail. */
580 ret
= SwitchDesktop(new_desk
);
581 ok(ret
, "SwitchDesktop failed!\n");
582 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
584 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
585 ok(input_desk
!= new_desk
, "returned the same handle!\n");
586 memset(name
, 0, sizeof(name
));
587 ret
= GetUserObjectInformationA(input_desk
, UOI_NAME
, name
, 1024, NULL
);
589 ok(ret
, "GetUserObjectInformation failed!\n");
591 ok(!strcmp(name
, "new_desk"), "unexpected desktop %s\n", name
);
592 ret
= CloseDesktop(input_desk
);
594 ok(ret
, "CloseDesktop failed!\n");
596 SetLastError(0xdeadbeef);
597 ret
= SendInput(1, inputs
, sizeof(INPUT
));
599 ok(GetLastError() == ERROR_ACCESS_DENIED
, "unexpected last error %08x\n", GetLastError());
600 ok(ret
== 1 || broken(ret
== 0) /* Win64 */, "unexpected return count %d\n", ret
);
602 /* Set thread desktop to the new desktop, SendInput should success. */
603 ret
= SetThreadDesktop(new_desk
);
604 ok(ret
, "SetThreadDesktop failed!\n");
605 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
606 ok(thread_desk
== new_desk
, "thread desktop doesn't match!\n");
607 memset(name
, 0, sizeof(name
));
608 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
609 ok(!strcmp(name
, "new_desk"), "unexpected desktop %s\n", name
);
611 SetLastError(0xdeadbeef);
612 ret
= SendInput(1, inputs
, sizeof(INPUT
));
613 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
614 ok(ret
== 1, "unexpected return count %d\n", ret
);
616 /* Switch input desktop to the old input desktop, set thread desktop to the old
617 * thread desktop, clean side effects. SendInput should success. */
618 ret
= SwitchDesktop(old_input_desk
);
619 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
621 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
623 ok(input_desk
!= old_input_desk
, "returned the same handle!\n");
624 memset(name
, 0, sizeof(name
));
625 ret
= GetUserObjectInformationA(input_desk
, UOI_NAME
, name
, 1024, NULL
);
627 ok(ret
, "GetUserObjectInformation failed!\n");
629 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
631 ret
= SetThreadDesktop(old_thread_desk
);
632 ok(ret
, "SetThreadDesktop failed!\n");
633 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
634 ok(thread_desk
== old_thread_desk
, "thread desktop doesn't match!\n");
635 memset(name
, 0, sizeof(name
));
636 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
637 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
639 SetLastError(0xdeadbeef);
640 ret
= SendInput(1, inputs
, sizeof(INPUT
));
641 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
642 ok(ret
== 1, "unexpected return count %d\n", ret
);
645 ret
= CloseDesktop(input_desk
);
647 ok(ret
, "CloseDesktop failed!\n");
648 ret
= CloseDesktop(old_input_desk
);
650 ok(ret
, "CloseDesktop failed!\n");
651 ret
= CloseDesktop(new_desk
);
652 ok(ret
, "CloseDesktop failed!\n");
655 static void test_inputdesktop2(void)
658 HDESK thread_desk
, new_desk
, input_desk
, hdesk
;
661 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
662 ok(thread_desk
!= NULL
, "GetThreadDesktop failed!\n");
663 w1
= GetProcessWindowStation();
664 ok(w1
!= NULL
, "GetProcessWindowStation failed!\n");
665 SetLastError(0xdeadbeef);
666 w2
= CreateWindowStation("winsta_test", 0, WINSTA_ALL_ACCESS
, NULL
);
667 ret
= GetLastError();
668 ok(w2
!= NULL
|| ret
== ERROR_ACCESS_DENIED
, "CreateWindowStation failed (%u)\n", ret
);
671 win_skip("Not enough privileges for CreateWindowStation\n");
675 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
676 ok(!ret
, "EnumDesktopsA failed!\n");
677 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
679 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
680 ret
= CloseDesktop(input_desk
);
682 ok(ret
, "CloseDesktop failed!\n");
684 ret
= SetProcessWindowStation(w2
);
685 ok(ret
, "SetProcessWindowStation failed!\n");
686 hdesk
= GetThreadDesktop(GetCurrentThreadId());
687 ok(hdesk
!= NULL
, "GetThreadDesktop failed!\n");
688 ok(hdesk
== thread_desk
, "thread desktop should not change after winstation changed!\n");
689 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
691 new_desk
= CreateDesktop("desk_test", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
692 ok(new_desk
!= NULL
, "CreateDesktop failed!\n");
693 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
694 ok(!ret
, "EnumDesktopsA failed!\n");
695 SetLastError(0xdeadbeef);
696 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
697 ok(input_desk
== NULL
, "OpenInputDesktop should fail on non default winstation!\n");
699 ok(GetLastError() == ERROR_INVALID_FUNCTION
|| broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
701 hdesk
= OpenDesktop("desk_test", 0, TRUE
, DESKTOP_ALL_ACCESS
);
702 ok(hdesk
!= NULL
, "OpenDesktop failed!\n");
703 SetLastError(0xdeadbeef);
704 ret
= SwitchDesktop(hdesk
);
706 ok(!ret
, "Switch to desktop belong to non default winstation should fail!\n");
708 ok(GetLastError() == ERROR_ACCESS_DENIED
|| broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
709 ret
= SetThreadDesktop(hdesk
);
710 ok(ret
, "SetThreadDesktop failed!\n");
712 /* clean side effect */
713 ret
= SetThreadDesktop(thread_desk
);
715 ok(ret
, "SetThreadDesktop should success even desktop is not belong to process winstation!\n");
716 ret
= SetProcessWindowStation(w1
);
717 ok(ret
, "SetProcessWindowStation failed!\n");
718 ret
= SetThreadDesktop(thread_desk
);
719 ok(ret
, "SetThreadDesktop failed!\n");
720 ret
= CloseWindowStation(w2
);
721 ok(ret
, "CloseWindowStation failed!\n");
722 ret
= CloseDesktop(new_desk
);
723 ok(ret
, "CloseDesktop failed!\n");
724 ret
= CloseDesktop(hdesk
);
725 ok(ret
, "CloseDesktop failed!\n");
728 static LRESULT CALLBACK
WndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
730 if (msg
== WM_DESTROY
)
732 trace("destroying hwnd %p\n", hWnd
);
736 return DefWindowProcA( hWnd
, msg
, wParam
, lParam
);
739 typedef struct tag_wnd_param
741 const char *wnd_name
;
747 static DWORD WINAPI
create_window(LPVOID param
)
749 wnd_param
*param1
= param
;
753 ret
= SetThreadDesktop(param1
->hdesk
);
754 ok(ret
, "SetThreadDesktop failed!\n");
755 param1
->hwnd
= CreateWindowA("test_class", param1
->wnd_name
, WS_POPUP
, 0, 0, 100, 100, NULL
, NULL
, NULL
, NULL
);
756 ok(param1
->hwnd
!= 0, "CreateWindowA failed!\n");
757 ret
= SetEvent(param1
->hevent
);
758 ok(ret
, "SetEvent failed!\n");
760 while (GetMessageA(&msg
, 0, 0, 0))
762 TranslateMessage(&msg
);
763 DispatchMessage(&msg
);
769 static DWORD
set_foreground(HWND hwnd
)
772 DWORD set_id
, fore_id
, ret
;
775 hwnd_fore
= GetForegroundWindow();
776 GetWindowText(hwnd_fore
, win_text
, 1024);
777 set_id
= GetWindowThreadProcessId(hwnd
, NULL
);
778 fore_id
= GetWindowThreadProcessId(hwnd_fore
, NULL
);
779 trace("\"%s\" %p %08x hwnd %p %08x\n", win_text
, hwnd_fore
, fore_id
, hwnd
, set_id
);
780 ret
= AttachThreadInput(set_id
, fore_id
, TRUE
);
781 trace("AttachThreadInput returned %08x\n", ret
);
782 ret
= ShowWindow(hwnd
, SW_SHOWNORMAL
);
783 trace("ShowWindow returned %08x\n", ret
);
784 ret
= SetWindowPos(hwnd
, HWND_TOPMOST
, 0,0,0,0, SWP_NOSIZE
|SWP_NOMOVE
);
785 trace("set topmost returned %08x\n", ret
);
786 ret
= SetWindowPos(hwnd
, HWND_NOTOPMOST
, 0,0,0,0, SWP_NOSIZE
|SWP_NOMOVE
);
787 trace("set notopmost returned %08x\n", ret
);
788 ret
= SetForegroundWindow(hwnd
);
789 trace("SetForegroundWindow returned %08x\n", ret
);
791 AttachThreadInput(set_id
, fore_id
, FALSE
);
795 static void test_foregroundwindow(void)
797 HWND hwnd
, hwnd_test
, partners
[2], hwnds
[2];
799 int thread_desk_id
, input_desk_id
, hwnd_id
;
802 DWORD ret
, timeout
, timeout_old
;
807 memset( &wclass
, 0, sizeof(wclass
) );
808 wclass
.lpszClassName
= "test_class";
809 wclass
.lpfnWndProc
= WndProc
;
810 RegisterClassA(&wclass
);
811 param
.wnd_name
= "win_name";
813 hdesks
[0] = GetThreadDesktop(GetCurrentThreadId());
814 ok(hdesks
[0] != NULL
, "OpenDesktop failed!\n");
815 SetLastError(0xdeadbeef);
816 hdesks
[1] = CreateDesktop("desk2", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
817 ret
= GetLastError();
818 ok(hdesks
[1] != NULL
|| ret
== ERROR_ACCESS_DENIED
, "CreateDesktop failed (%u)\n", ret
);
821 win_skip("Not enough privileges for CreateDesktop\n");
825 ret
= SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT
, 0, &timeout_old
, 0);
828 win_skip("Skip tests on NT4\n");
829 CloseDesktop(hdesks
[1]);
832 trace("old timeout %d\n", timeout_old
);
834 ret
= SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT
, 0, 0, SPIF_SENDCHANGE
| SPIF_UPDATEINIFILE
);
835 ok(ret
, "set foreground lock timeout failed!\n");
836 ret
= SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT
, 0, &timeout
, 0);
837 ok(ret
, "get foreground lock timeout failed!\n");
838 ok(timeout
== 0, "unexpected timeout %d\n", timeout
);
840 for (thread_desk_id
= 0; thread_desk_id
< DESKTOPS
; thread_desk_id
++)
842 param
.hdesk
= hdesks
[thread_desk_id
];
843 param
.hevent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
844 CreateThread(NULL
, 0, create_window
, ¶m
, 0, NULL
);
845 ret
= WaitForSingleObject(param
.hevent
, INFINITE
);
846 ok(ret
== WAIT_OBJECT_0
, "wait failed!\n");
847 hwnds
[thread_desk_id
] = param
.hwnd
;
850 for (thread_desk_id
= 0; thread_desk_id
< DESKTOPS
; thread_desk_id
++)
852 param
.hdesk
= hdesks
[thread_desk_id
];
853 param
.hevent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
854 CreateThread(NULL
, 0, create_window
, ¶m
, 0, NULL
);
855 ret
= WaitForSingleObject(param
.hevent
, INFINITE
);
856 ok(ret
== WAIT_OBJECT_0
, "wait failed!\n");
857 partners
[thread_desk_id
] = param
.hwnd
;
860 trace("hwnd0 %p hwnd1 %p partner0 %p partner1 %p\n", hwnds
[0], hwnds
[1], partners
[0], partners
[1]);
862 for (hwnd_id
= 0; hwnd_id
< DESKTOPS
; hwnd_id
++)
863 for (thread_desk_id
= 0; thread_desk_id
< DESKTOPS
; thread_desk_id
++)
864 for (input_desk_id
= 0; input_desk_id
< DESKTOPS
; input_desk_id
++)
866 trace("testing thread_desk %d input_desk %d hwnd %d\n",
867 thread_desk_id
, input_desk_id
, hwnd_id
);
868 hwnd_test
= hwnds
[hwnd_id
];
869 ret
= SetThreadDesktop(hdesks
[thread_desk_id
]);
870 ok(ret
, "set thread desktop failed!\n");
871 ret
= SwitchDesktop(hdesks
[input_desk_id
]);
872 ok(ret
, "switch desktop failed!\n");
873 set_foreground(partners
[0]);
874 set_foreground(partners
[1]);
875 hwnd
= GetForegroundWindow();
876 ok(hwnd
!= hwnd_test
, "unexpected foreground window %p\n", hwnd
);
877 ret
= set_foreground(hwnd_test
);
878 hwnd
= GetForegroundWindow();
879 GetWindowText(hwnd
, win_text
, 1024);
880 trace("hwnd %p name %s\n", hwnd
, win_text
);
881 if (input_desk_id
== hwnd_id
)
883 if (input_desk_id
== thread_desk_id
)
885 ok(ret
, "SetForegroundWindow failed!\n");
886 ok(hwnd
== hwnd_test
, "unexpected foreground window %p\n", hwnd
);
890 todo_wine
ok(ret
, "SetForegroundWindow failed!\n");
891 todo_wine
ok(hwnd
== 0, "unexpected foreground window %p\n", hwnd
);
896 if (input_desk_id
== thread_desk_id
)
898 ok(!ret
, "SetForegroundWindow should fail!\n");
899 ok(hwnd
== partners
[input_desk_id
] , "unexpected foreground window %p\n", hwnd
);
903 todo_wine
ok(!ret
, "SetForegroundWindow should fail!\n");
904 todo_wine
ok(hwnd
== 0, "unexpected foreground window %p\n", hwnd
);
911 for (thread_desk_id
= DESKTOPS
- 1; thread_desk_id
>= 0; thread_desk_id
--)
913 ret
= SetThreadDesktop(hdesks
[thread_desk_id
]);
914 ok(ret
, "set thread desktop failed!\n");
915 SendMessage(hwnds
[thread_desk_id
], WM_DESTROY
, 0, 0);
916 SendMessage(partners
[thread_desk_id
], WM_DESTROY
, 0, 0);
919 ret
= SwitchDesktop(hdesks
[0]);
920 ok(ret
, "switch desktop failed!\n");
921 CloseDesktop(hdesks
[1]);
923 ret
= SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT
, 0, UlongToPtr(timeout_old
), SPIF_SENDCHANGE
| SPIF_UPDATEINIFILE
);
924 ok(ret
, "set foreground lock timeout failed!\n");
925 ret
= SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT
, 0, &timeout
, 0);
926 ok(ret
, "get foreground lock timeout failed!\n");
927 ok(timeout
== timeout_old
, "unexpected timeout %d\n", timeout
);
930 START_TEST(winstation
)
932 /* Check whether this platform supports WindowStation calls */
934 SetLastError( 0xdeadbeef );
935 GetProcessWindowStation();
936 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
938 skip("WindowStation calls not supported on this platform\n");
943 test_inputdesktop2();
947 test_getuserobjectinformation();
948 test_foregroundwindow();