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, (LPCSTR
)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
= CreateDesktopA( "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
= CreateWindowStationA("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
= CreateWindowStationA("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
= OpenWindowStationA("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
= OpenWindowStationA("dummy name", TRUE
, WINSTA_ALL_ACCESS
);
163 ok( !w2
, "open dummy win station succeeded\n" );
165 CreateMutexA( NULL
, 0, "foobar" );
166 w2
= CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS
, NULL
);
168 ok( w2
!= 0 || le
== ERROR_ACCESS_DENIED
, "create foobar station failed (%u)\n", le
);
172 w3
= OpenWindowStationA("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
= OpenWindowStationA("foobar", TRUE
, WINSTA_ALL_ACCESS
);
179 ok( !w3
, "open foobar station succeeded\n" );
181 w2
= CreateWindowStationA("foobar1", 0, WINSTA_ALL_ACCESS
, NULL
);
182 ok( w2
!= 0, "create foobar station failed\n" );
183 w3
= CreateWindowStationA("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
= OpenDesktopA( "dummy name", 0, TRUE
, DESKTOP_ALL_ACCESS
);
237 ok( !d2
, "open dummy desktop succeeded\n" );
239 d2
= CreateDesktopA( "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
= CreateDesktopA( "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
= OpenDesktopA( "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
= OpenDesktopA( "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)
303 if (0) /* Crashes instead */
305 SetLastError(0xbabefeed);
306 ret
= EnumWindowStationsA(NULL
, 0);
307 ok(!ret
, "EnumWindowStationsA returned successfully!\n");
308 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "LastError is set to %08x\n", GetLastError());
311 hwinsta
= CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS
, NULL
);
312 ret
= GetLastError();
313 ok(hwinsta
!= NULL
|| ret
== ERROR_ACCESS_DENIED
, "CreateWindowStation failed (%u)\n", ret
);
316 win_skip("Not enough privileges for CreateWindowStation\n");
320 SetLastError(0xdeadbeef);
321 ret
= EnumWindowStationsA(open_window_station_callbackA
, 0x12345);
322 ok(ret
== 0x12345, "EnumWindowStationsA returned %x\n", ret
);
323 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
325 SetLastError(0xdeadbeef);
326 ret
= EnumWindowStationsA(window_station_callbackA
, 0);
327 ok(!ret
, "EnumWindowStationsA returned %x\n", ret
);
328 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
331 static BOOL CALLBACK
desktop_callbackA(LPSTR desktop
, LPARAM lp
)
333 trace("desktop_callbackA called with argument %s\n", desktop
);
337 static BOOL CALLBACK
open_desktop_callbackA(LPSTR desktop
, LPARAM lp
)
342 trace("open_desktop_callbackA called with argument %s\n", desktop
);
343 /* Only try to open one desktop */
347 hdesk
= OpenDesktopA(desktop
, 0, FALSE
, DESKTOP_ENUMERATE
);
348 ok(hdesk
!= NULL
, "Could not open desktop %s!\n", desktop
);
354 static void test_enumdesktops(void)
358 if (0) /* Crashes instead */
360 SetLastError(0xbabefeed);
361 ret
= EnumDesktopsA(GetProcessWindowStation(), NULL
, 0);
362 ok(!ret
, "EnumDesktopsA returned successfully!\n");
363 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "LastError is set to %08x\n", GetLastError());
366 SetLastError(0xdeadbeef);
367 ret
= EnumDesktopsA(NULL
, desktop_callbackA
, 0x12345);
368 ok(ret
== 0x12345, "EnumDesktopsA returned %x\n", ret
);
369 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
371 SetLastError(0xdeadbeef);
372 ret
= EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA
, 0x12345);
373 ok(ret
== 0x12345, "EnumDesktopsA returned %x\n", ret
);
374 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
376 SetLastError(0xdeadbeef);
377 ret
= EnumDesktopsA(INVALID_HANDLE_VALUE
, desktop_callbackA
, 0x12345);
378 ok(!ret
, "EnumDesktopsA returned %x\n", ret
);
379 ok(GetLastError() == ERROR_INVALID_HANDLE
, "LastError is set to %08x\n", GetLastError());
381 SetLastError(0xdeadbeef);
382 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
383 ok(!ret
, "EnumDesktopsA returned %x\n", ret
);
384 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
387 /* Miscellaneous tests */
389 static void test_getuserobjectinformation(void)
394 WCHAR foobarTestW
[] = {'f','o','o','b','a','r','T','e','s','t',0};
395 WCHAR DesktopW
[] = {'D','e','s','k','t','o','p',0};
399 desk
= CreateDesktopA("foobarTest", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
400 ok(desk
!= 0, "open foobarTest desktop failed\n");
402 strcpy(buffer
, "blahblah");
404 /** Tests for UOI_NAME **/
406 /* Get size, test size and return value/error code */
407 SetLastError(0xdeadbeef);
409 ret
= GetUserObjectInformationA(desk
, UOI_NAME
, NULL
, 0, &size
);
411 ok(!ret
, "GetUserObjectInformationA returned %x\n", ret
);
412 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
413 ok(size
== 22, "size is set to %d\n", size
); /* Windows returns Unicode length (11*2) */
416 SetLastError(0xdeadbeef);
418 ret
= GetUserObjectInformationA(desk
, UOI_NAME
, buffer
, sizeof(buffer
), &size
);
420 ok(ret
, "GetUserObjectInformationA returned %x\n", ret
);
421 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
423 ok(strcmp(buffer
, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer
);
424 ok(size
== 11, "size is set to %d\n", size
); /* 11 bytes in 'foobarTest\0' */
426 /* Get size, test size and return value/error code (Unicode) */
427 SetLastError(0xdeadbeef);
429 ret
= GetUserObjectInformationW(desk
, UOI_NAME
, NULL
, 0, &size
);
431 ok(!ret
, "GetUserObjectInformationW returned %x\n", ret
);
432 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
433 ok(size
== 22, "size is set to %d\n", size
); /* 22 bytes in 'foobarTest\0' in Unicode */
435 /* Get string (Unicode) */
436 SetLastError(0xdeadbeef);
438 ret
= GetUserObjectInformationW(desk
, UOI_NAME
, bufferW
, sizeof(bufferW
), &size
);
440 ok(ret
, "GetUserObjectInformationW returned %x\n", ret
);
441 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
443 ok(lstrcmpW(bufferW
, foobarTestW
) == 0, "Buffer is not set to 'foobarTest'\n");
444 ok(size
== 22, "size is set to %d\n", size
); /* 22 bytes in 'foobarTest\0' in Unicode */
446 /** Tests for UOI_TYPE **/
448 /* Get size, test size and return value/error code */
449 SetLastError(0xdeadbeef);
451 ret
= GetUserObjectInformationA(desk
, UOI_TYPE
, NULL
, 0, &size
);
453 ok(!ret
, "GetUserObjectInformationA returned %x\n", ret
);
454 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
455 ok(size
== 16, "size is set to %d\n", size
); /* Windows returns Unicode length (8*2) */
458 SetLastError(0xdeadbeef);
460 ret
= GetUserObjectInformationA(desk
, UOI_TYPE
, buffer
, sizeof(buffer
), &size
);
462 ok(ret
, "GetUserObjectInformationA returned %x\n", ret
);
463 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
465 ok(strcmp(buffer
, "Desktop") == 0, "Buffer is set to '%s'\n", buffer
);
466 ok(size
== 8, "size is set to %d\n", size
); /* 8 bytes in 'Desktop\0' */
468 /* Get size, test size and return value/error code (Unicode) */
470 SetLastError(0xdeadbeef);
471 ret
= GetUserObjectInformationW(desk
, UOI_TYPE
, NULL
, 0, &size
);
473 ok(!ret
, "GetUserObjectInformationW returned %x\n", ret
);
474 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "LastError is set to %08x\n", GetLastError());
475 ok(size
== 16, "size is set to %d\n", size
); /* 16 bytes in 'Desktop\0' in Unicode */
477 /* Get string (Unicode) */
478 SetLastError(0xdeadbeef);
480 ret
= GetUserObjectInformationW(desk
, UOI_TYPE
, bufferW
, sizeof(bufferW
), &size
);
482 ok(ret
, "GetUserObjectInformationW returned %x\n", ret
);
483 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
485 ok(lstrcmpW(bufferW
, DesktopW
) == 0, "Buffer is not set to 'Desktop'\n");
486 ok(size
== 16, "size is set to %d\n", size
); /* 16 bytes in 'Desktop\0' in Unicode */
488 ok(CloseDesktop(desk
), "CloseDesktop failed\n");
491 static void test_inputdesktop(void)
493 HDESK input_desk
, old_input_desk
, thread_desk
, old_thread_desk
, new_desk
;
498 inputs
[0].type
= INPUT_KEYBOARD
;
499 U(inputs
[0]).ki
.wVk
= 0;
500 U(inputs
[0]).ki
.wScan
= 0x3c0;
501 U(inputs
[0]).ki
.dwFlags
= KEYEVENTF_UNICODE
;
503 /* OpenInputDesktop creates new handles for each calls */
504 old_input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
505 ok(old_input_desk
!= NULL
, "OpenInputDesktop failed!\n");
506 memset(name
, 0, sizeof(name
));
507 ret
= GetUserObjectInformationA(old_input_desk
, UOI_NAME
, name
, 1024, NULL
);
508 ok(ret
, "GetUserObjectInformation failed!\n");
509 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
511 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
512 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
513 memset(name
, 0, sizeof(name
));
514 ret
= GetUserObjectInformationA(input_desk
, UOI_NAME
, name
, 1024, NULL
);
515 ok(ret
, "GetUserObjectInformation failed!\n");
516 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
518 ok(old_input_desk
!= input_desk
, "returned the same handle!\n");
519 ret
= CloseDesktop(input_desk
);
520 ok(ret
, "CloseDesktop failed!\n");
522 /* by default, GetThreadDesktop is the input desktop, SendInput should succeed. */
523 old_thread_desk
= GetThreadDesktop(GetCurrentThreadId());
524 ok(old_thread_desk
!= NULL
, "GetThreadDesktop faile!\n");
525 memset(name
, 0, sizeof(name
));
526 ret
= GetUserObjectInformationA(old_thread_desk
, UOI_NAME
, name
, 1024, NULL
);
527 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
529 SetLastError(0xdeadbeef);
530 ret
= SendInput(1, inputs
, sizeof(INPUT
));
531 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
532 ok(ret
== 1, "unexpected return count %d\n", ret
);
534 /* Set thread desktop to the new desktop, SendInput should fail. */
535 new_desk
= CreateDesktopA("new_desk", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
536 ok(new_desk
!= NULL
, "CreateDesktop failed!\n");
537 ret
= SetThreadDesktop(new_desk
);
538 ok(ret
, "SetThreadDesktop failed!\n");
539 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
540 ok(thread_desk
== new_desk
, "thread desktop doesn't match!\n");
541 memset(name
, 0, sizeof(name
));
542 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
543 ok(!strcmp(name
, "new_desk"), "unexpected desktop %s\n", name
);
545 SetLastError(0xdeadbeef);
546 ret
= SendInput(1, inputs
, sizeof(INPUT
));
547 if(broken(GetLastError() == 0xdeadbeef))
549 SetThreadDesktop(old_thread_desk
);
550 CloseDesktop(old_input_desk
);
551 CloseDesktop(input_desk
);
552 CloseDesktop(new_desk
);
553 win_skip("Skip tests on NT4\n");
557 ok(GetLastError() == ERROR_ACCESS_DENIED
, "unexpected last error %08x\n", GetLastError());
558 ok(ret
== 1 || broken(ret
== 0) /* Win64 */, "unexpected return count %d\n", ret
);
560 /* Set thread desktop back to the old thread desktop, SendInput should success. */
561 ret
= SetThreadDesktop(old_thread_desk
);
562 ok(ret
, "SetThreadDesktop failed!\n");
563 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
564 ok(thread_desk
== old_thread_desk
, "thread desktop doesn't match!\n");
565 memset(name
, 0, sizeof(name
));
566 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
567 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
569 SetLastError(0xdeadbeef);
570 ret
= SendInput(1, inputs
, sizeof(INPUT
));
571 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
572 ok(ret
== 1, "unexpected return count %d\n", ret
);
574 /* Set thread desktop to the input desktop, SendInput should success. */
575 ret
= SetThreadDesktop(old_input_desk
);
576 ok(ret
, "SetThreadDesktop failed!\n");
577 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
578 ok(thread_desk
== old_input_desk
, "thread desktop doesn't match!\n");
579 memset(name
, 0, sizeof(name
));
580 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
581 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
583 SetLastError(0xdeadbeef);
584 ret
= SendInput(1, inputs
, sizeof(INPUT
));
585 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
586 ok(ret
== 1, "unexpected return count %d\n", ret
);
588 /* Switch input desktop to the new desktop, SendInput should fail. */
589 ret
= SwitchDesktop(new_desk
);
590 ok(ret
, "SwitchDesktop failed!\n");
591 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
592 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
593 ok(input_desk
!= new_desk
, "returned the same handle!\n");
594 memset(name
, 0, sizeof(name
));
595 ret
= GetUserObjectInformationA(input_desk
, UOI_NAME
, name
, 1024, NULL
);
596 ok(ret
, "GetUserObjectInformation failed!\n");
598 ok(!strcmp(name
, "new_desk"), "unexpected desktop %s\n", name
);
599 ret
= CloseDesktop(input_desk
);
600 ok(ret
, "CloseDesktop failed!\n");
602 SetLastError(0xdeadbeef);
603 ret
= SendInput(1, inputs
, sizeof(INPUT
));
605 ok(GetLastError() == ERROR_ACCESS_DENIED
, "unexpected last error %08x\n", GetLastError());
606 ok(ret
== 1 || broken(ret
== 0) /* Win64 */, "unexpected return count %d\n", ret
);
608 /* Set thread desktop to the new desktop, SendInput should success. */
609 ret
= SetThreadDesktop(new_desk
);
610 ok(ret
, "SetThreadDesktop failed!\n");
611 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
612 ok(thread_desk
== new_desk
, "thread desktop doesn't match!\n");
613 memset(name
, 0, sizeof(name
));
614 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
615 ok(!strcmp(name
, "new_desk"), "unexpected desktop %s\n", name
);
617 SetLastError(0xdeadbeef);
618 ret
= SendInput(1, inputs
, sizeof(INPUT
));
619 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
620 ok(ret
== 1, "unexpected return count %d\n", ret
);
622 /* Switch input desktop to the old input desktop, set thread desktop to the old
623 * thread desktop, clean side effects. SendInput should success. */
624 ret
= SwitchDesktop(old_input_desk
);
625 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
626 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
627 ok(input_desk
!= old_input_desk
, "returned the same handle!\n");
628 memset(name
, 0, sizeof(name
));
629 ret
= GetUserObjectInformationA(input_desk
, UOI_NAME
, name
, 1024, NULL
);
630 ok(ret
, "GetUserObjectInformation failed!\n");
631 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
633 ret
= SetThreadDesktop(old_thread_desk
);
634 ok(ret
, "SetThreadDesktop failed!\n");
635 thread_desk
= GetThreadDesktop(GetCurrentThreadId());
636 ok(thread_desk
== old_thread_desk
, "thread desktop doesn't match!\n");
637 memset(name
, 0, sizeof(name
));
638 ret
= GetUserObjectInformationA(thread_desk
, UOI_NAME
, name
, 1024, NULL
);
639 ok(!strcmp(name
, "Default"), "unexpected desktop %s\n", name
);
641 SetLastError(0xdeadbeef);
642 ret
= SendInput(1, inputs
, sizeof(INPUT
));
643 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
644 ok(ret
== 1, "unexpected return count %d\n", ret
);
647 ret
= CloseDesktop(input_desk
);
648 ok(ret
, "CloseDesktop failed!\n");
649 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
= CreateWindowStationA("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
);
678 ok(input_desk
!= NULL
, "OpenInputDesktop failed!\n");
679 ret
= CloseDesktop(input_desk
);
680 ok(ret
, "CloseDesktop failed!\n");
682 ret
= SetProcessWindowStation(w2
);
683 ok(ret
, "SetProcessWindowStation failed!\n");
684 hdesk
= GetThreadDesktop(GetCurrentThreadId());
685 ok(hdesk
!= NULL
, "GetThreadDesktop failed!\n");
686 ok(hdesk
== thread_desk
, "thread desktop should not change after winstation changed!\n");
687 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
689 new_desk
= CreateDesktopA("desk_test", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
690 ok(new_desk
!= NULL
, "CreateDesktop failed!\n");
691 ret
= EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA
, 0);
692 ok(!ret
, "EnumDesktopsA failed!\n");
693 SetLastError(0xdeadbeef);
694 input_desk
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
695 ok(input_desk
== NULL
, "OpenInputDesktop should fail on non default winstation!\n");
696 ok(GetLastError() == ERROR_INVALID_FUNCTION
|| broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
698 hdesk
= OpenDesktopA("desk_test", 0, TRUE
, DESKTOP_ALL_ACCESS
);
699 ok(hdesk
!= NULL
, "OpenDesktop failed!\n");
700 SetLastError(0xdeadbeef);
701 ret
= SwitchDesktop(hdesk
);
703 ok(!ret
, "Switch to desktop belong to non default winstation should fail!\n");
705 ok(GetLastError() == ERROR_ACCESS_DENIED
|| broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
706 ret
= SetThreadDesktop(hdesk
);
707 ok(ret
, "SetThreadDesktop failed!\n");
709 /* clean side effect */
710 ret
= SetThreadDesktop(thread_desk
);
712 ok(ret
, "SetThreadDesktop should success even desktop is not belong to process winstation!\n");
713 ret
= SetProcessWindowStation(w1
);
714 ok(ret
, "SetProcessWindowStation failed!\n");
715 ret
= SetThreadDesktop(thread_desk
);
716 ok(ret
, "SetThreadDesktop failed!\n");
717 ret
= CloseWindowStation(w2
);
718 ok(ret
, "CloseWindowStation failed!\n");
719 ret
= CloseDesktop(new_desk
);
720 ok(ret
, "CloseDesktop failed!\n");
721 ret
= CloseDesktop(hdesk
);
722 ok(ret
, "CloseDesktop failed!\n");
725 static LRESULT CALLBACK
WndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
727 if (msg
== WM_DESTROY
)
729 trace("destroying hwnd %p\n", hWnd
);
733 return DefWindowProcA( hWnd
, msg
, wParam
, lParam
);
736 typedef struct tag_wnd_param
738 const char *wnd_name
;
744 static DWORD WINAPI
create_window(LPVOID param
)
746 wnd_param
*param1
= param
;
750 ret
= SetThreadDesktop(param1
->hdesk
);
751 ok(ret
, "SetThreadDesktop failed!\n");
752 param1
->hwnd
= CreateWindowA("test_class", param1
->wnd_name
, WS_POPUP
, 0, 0, 100, 100, NULL
, NULL
, NULL
, NULL
);
753 ok(param1
->hwnd
!= 0, "CreateWindowA failed!\n");
754 ret
= SetEvent(param1
->hevent
);
755 ok(ret
, "SetEvent failed!\n");
757 while (GetMessageA(&msg
, 0, 0, 0))
759 TranslateMessage(&msg
);
760 DispatchMessageA(&msg
);
766 static DWORD
set_foreground(HWND hwnd
)
769 DWORD set_id
, fore_id
, ret
;
772 hwnd_fore
= GetForegroundWindow();
773 GetWindowTextA(hwnd_fore
, win_text
, 1024);
774 set_id
= GetWindowThreadProcessId(hwnd
, NULL
);
775 fore_id
= GetWindowThreadProcessId(hwnd_fore
, NULL
);
776 trace("\"%s\" %p %08x hwnd %p %08x\n", win_text
, hwnd_fore
, fore_id
, hwnd
, set_id
);
777 ret
= AttachThreadInput(set_id
, fore_id
, TRUE
);
778 trace("AttachThreadInput returned %08x\n", ret
);
779 ret
= ShowWindow(hwnd
, SW_SHOWNORMAL
);
780 trace("ShowWindow returned %08x\n", ret
);
781 ret
= SetWindowPos(hwnd
, HWND_TOPMOST
, 0,0,0,0, SWP_NOSIZE
|SWP_NOMOVE
);
782 trace("set topmost returned %08x\n", ret
);
783 ret
= SetWindowPos(hwnd
, HWND_NOTOPMOST
, 0,0,0,0, SWP_NOSIZE
|SWP_NOMOVE
);
784 trace("set notopmost returned %08x\n", ret
);
785 ret
= SetForegroundWindow(hwnd
);
786 trace("SetForegroundWindow returned %08x\n", ret
);
788 AttachThreadInput(set_id
, fore_id
, FALSE
);
792 static void test_foregroundwindow(void)
794 HWND hwnd
, hwnd_test
, partners
[2], hwnds
[2];
796 int thread_desk_id
, input_desk_id
, hwnd_id
;
799 DWORD ret
, timeout
, timeout_old
;
804 memset( &wclass
, 0, sizeof(wclass
) );
805 wclass
.lpszClassName
= "test_class";
806 wclass
.lpfnWndProc
= WndProc
;
807 RegisterClassA(&wclass
);
808 param
.wnd_name
= "win_name";
810 hdesks
[0] = GetThreadDesktop(GetCurrentThreadId());
811 ok(hdesks
[0] != NULL
, "OpenDesktop failed!\n");
812 SetLastError(0xdeadbeef);
813 hdesks
[1] = CreateDesktopA("desk2", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
814 ret
= GetLastError();
815 ok(hdesks
[1] != NULL
|| ret
== ERROR_ACCESS_DENIED
, "CreateDesktop failed (%u)\n", ret
);
818 win_skip("Not enough privileges for CreateDesktop\n");
822 ret
= SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT
, 0, &timeout_old
, 0);
825 win_skip("Skip tests on NT4\n");
826 CloseDesktop(hdesks
[1]);
829 trace("old timeout %d\n", timeout_old
);
831 ret
= SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT
, 0, 0, SPIF_SENDCHANGE
| SPIF_UPDATEINIFILE
);
832 ok(ret
, "set foreground lock timeout failed!\n");
833 ret
= SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT
, 0, &timeout
, 0);
834 ok(ret
, "get foreground lock timeout failed!\n");
835 ok(timeout
== 0, "unexpected timeout %d\n", timeout
);
837 for (thread_desk_id
= 0; thread_desk_id
< DESKTOPS
; thread_desk_id
++)
839 param
.hdesk
= hdesks
[thread_desk_id
];
840 param
.hevent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
841 CreateThread(NULL
, 0, create_window
, ¶m
, 0, NULL
);
842 ret
= WaitForSingleObject(param
.hevent
, INFINITE
);
843 ok(ret
== WAIT_OBJECT_0
, "wait failed!\n");
844 hwnds
[thread_desk_id
] = param
.hwnd
;
847 for (thread_desk_id
= 0; thread_desk_id
< DESKTOPS
; thread_desk_id
++)
849 param
.hdesk
= hdesks
[thread_desk_id
];
850 param
.hevent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
851 CreateThread(NULL
, 0, create_window
, ¶m
, 0, NULL
);
852 ret
= WaitForSingleObject(param
.hevent
, INFINITE
);
853 ok(ret
== WAIT_OBJECT_0
, "wait failed!\n");
854 partners
[thread_desk_id
] = param
.hwnd
;
857 trace("hwnd0 %p hwnd1 %p partner0 %p partner1 %p\n", hwnds
[0], hwnds
[1], partners
[0], partners
[1]);
859 for (hwnd_id
= 0; hwnd_id
< DESKTOPS
; hwnd_id
++)
860 for (thread_desk_id
= 0; thread_desk_id
< DESKTOPS
; thread_desk_id
++)
861 for (input_desk_id
= 0; input_desk_id
< DESKTOPS
; input_desk_id
++)
863 trace("testing thread_desk %d input_desk %d hwnd %d\n",
864 thread_desk_id
, input_desk_id
, hwnd_id
);
865 hwnd_test
= hwnds
[hwnd_id
];
866 ret
= SetThreadDesktop(hdesks
[thread_desk_id
]);
867 ok(ret
, "set thread desktop failed!\n");
868 ret
= SwitchDesktop(hdesks
[input_desk_id
]);
869 ok(ret
, "switch desktop failed!\n");
870 set_foreground(partners
[0]);
871 set_foreground(partners
[1]);
872 hwnd
= GetForegroundWindow();
873 ok(hwnd
!= hwnd_test
, "unexpected foreground window %p\n", hwnd
);
874 ret
= set_foreground(hwnd_test
);
875 hwnd
= GetForegroundWindow();
876 GetWindowTextA(hwnd
, win_text
, 1024);
877 trace("hwnd %p name %s\n", hwnd
, win_text
);
878 if (input_desk_id
== hwnd_id
)
880 if (input_desk_id
== thread_desk_id
)
882 ok(ret
, "SetForegroundWindow failed!\n");
884 ok(hwnd
== hwnd_test
, "unexpected foreground window %p\n", hwnd
);
886 todo_wine
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");
900 ok(hwnd
== partners
[input_desk_id
] , "unexpected foreground window %p\n", hwnd
);
902 todo_wine
ok(hwnd
== partners
[input_desk_id
] , "unexpected foreground window %p\n", hwnd
);
906 todo_wine
ok(!ret
, "SetForegroundWindow should fail!\n");
908 ok(hwnd
== 0, "unexpected foreground window %p\n", hwnd
);
910 todo_wine
ok(hwnd
== 0, "unexpected foreground window %p\n", hwnd
);
917 for (thread_desk_id
= DESKTOPS
- 1; thread_desk_id
>= 0; thread_desk_id
--)
919 ret
= SetThreadDesktop(hdesks
[thread_desk_id
]);
920 ok(ret
, "set thread desktop failed!\n");
921 SendMessageA(hwnds
[thread_desk_id
], WM_DESTROY
, 0, 0);
922 SendMessageA(partners
[thread_desk_id
], WM_DESTROY
, 0, 0);
925 ret
= SwitchDesktop(hdesks
[0]);
926 ok(ret
, "switch desktop failed!\n");
927 CloseDesktop(hdesks
[1]);
929 ret
= SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT
, 0, UlongToPtr(timeout_old
), SPIF_SENDCHANGE
| SPIF_UPDATEINIFILE
);
930 ok(ret
, "set foreground lock timeout failed!\n");
931 ret
= SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT
, 0, &timeout
, 0);
932 ok(ret
, "get foreground lock timeout failed!\n");
933 ok(timeout
== timeout_old
, "unexpected timeout %d\n", timeout
);
936 START_TEST(winstation
)
938 /* Check whether this platform supports WindowStation calls */
940 SetLastError( 0xdeadbeef );
941 GetProcessWindowStation();
942 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
944 win_skip("WindowStation calls not supported on this platform\n");
949 test_inputdesktop2();
953 test_getuserobjectinformation();
954 test_foregroundwindow();