mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / user32 / tests / winstation.c
blob76aa8a533b97e8f55ea1275ed845661fb7ca0397
1 /*
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"
22 #include "winbase.h"
23 #include "wingdi.h"
24 #include "winuser.h"
25 #include "winnls.h"
26 #include "winternl.h"
28 static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
30 #define DESKTOP_ALL_ACCESS 0x01ff
32 static void print_object( HANDLE obj )
34 char buffer[100];
35 DWORD size;
37 strcpy( buffer, "foobar" );
38 if (!GetUserObjectInformationA( obj, UOI_NAME, buffer, sizeof(buffer), &size ))
39 trace( "could not get info for %p\n", obj );
40 else
41 trace( "obj %p name '%s'\n", obj, buffer );
42 strcpy( buffer, "foobar" );
43 if (!GetUserObjectInformationA( obj, UOI_TYPE, buffer, sizeof(buffer), &size ))
44 trace( "could not get type for %p\n", obj );
45 else
46 trace( "obj %p type '%s'\n", obj, buffer );
49 static void register_class(void)
51 WNDCLASSA cls;
53 cls.style = CS_DBLCLKS;
54 /* Windows < Vista apparently checks lpfnWndProc against the address of
55 * DefWindowProcA(), and for some reason fails to change the thread desktop
56 * after creating and destroying a window if it doesn't match. Using an IAT
57 * (as is default) or a wrapper triggers this, so use GetProcAddress() as
58 * a workaround. */
59 cls.lpfnWndProc = (void *)GetProcAddress(GetModuleHandleA("user32"), "DefWindowProcA");
60 cls.cbClsExtra = 0;
61 cls.cbWndExtra = 0;
62 cls.hInstance = GetModuleHandleA(0);
63 cls.hIcon = 0;
64 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
65 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
66 cls.lpszMenuName = NULL;
67 cls.lpszClassName = "WinStationClass";
68 RegisterClassA(&cls);
71 static HDESK initial_desktop;
73 static DWORD CALLBACK thread( LPVOID arg )
75 HDESK d1, d2;
76 HWND hwnd = CreateWindowExA(0,"WinStationClass","test",WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
77 ok( hwnd != 0, "CreateWindow failed\n" );
78 d1 = GetThreadDesktop(GetCurrentThreadId());
79 trace( "thread %p desktop: %p\n", arg, d1 );
80 ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg );
82 SetLastError( 0xdeadbeef );
83 ok( !CloseHandle( d1 ), "CloseHandle succeeded\n" );
84 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
85 SetLastError( 0xdeadbeef );
86 ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" );
87 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
88 "bad last error %d\n", GetLastError() );
89 print_object( d1 );
90 d2 = CreateDesktopA( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
91 trace( "created desktop %p\n", d2 );
92 ok( d2 != 0, "CreateDesktop failed\n" );
94 SetLastError( 0xdeadbeef );
95 ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
96 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
97 "bad last error %d\n", GetLastError() );
99 DestroyWindow( hwnd );
100 ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" );
101 d1 = GetThreadDesktop(GetCurrentThreadId());
102 ok( d1 == d2, "GetThreadDesktop did not return set desktop %p/%p\n", d1, d2 );
103 print_object( d2 );
104 if (arg < (LPVOID)5)
106 HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL );
107 Sleep(1000);
108 WaitForSingleObject( hthread, INFINITE );
109 CloseHandle( hthread );
111 return 0;
114 static void test_handles(void)
116 HWINSTA w1, w2, w3;
117 HDESK d1, d2, d3;
118 HANDLE hthread;
119 DWORD id, flags, le;
120 ATOM atom;
121 char buffer[29], default_name[29] = "";
122 DWORD size;
123 BOOL ret;
124 TOKEN_STATISTICS token_stats;
126 /* win stations */
128 w1 = GetProcessWindowStation();
129 ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" );
130 ok( !CloseWindowStation(w1), "closing process win station succeeded\n" );
131 SetLastError( 0xdeadbeef );
132 ok( !CloseHandle(w1), "closing process win station handle succeeded\n" );
133 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
134 print_object( w1 );
136 flags = 0;
137 ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
138 ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ||
139 broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */
140 "handle %p PROTECT_FROM_CLOSE set\n", w1 );
142 ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
143 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
144 ok( CloseWindowStation(w2), "closing dup win station failed\n" );
146 ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
147 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
148 ok( CloseHandle(w2), "closing dup win station handle failed\n" );
150 w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
151 le = GetLastError();
152 ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", le );
153 if (w2 != 0)
155 ok( w2 != w1, "CreateWindowStation returned default handle\n" );
156 SetLastError( 0xdeadbeef );
157 ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" );
158 ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */
159 "bad last error %d\n", GetLastError() );
160 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
162 w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
163 ok( CloseHandle( w2 ), "CloseHandle failed\n" );
165 else if (le == ERROR_ACCESS_DENIED)
166 win_skip( "Not enough privileges for CreateWindowStation\n" );
168 w2 = OpenWindowStationA("winsta0", TRUE, WINSTA_ALL_ACCESS );
169 ok( w2 != 0, "OpenWindowStation failed\n" );
170 ok( w2 != w1, "OpenWindowStation returned default handle\n" );
171 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
173 w2 = OpenWindowStationA("dummy name", TRUE, WINSTA_ALL_ACCESS );
174 ok( !w2, "open dummy win station succeeded\n" );
176 CreateMutexA( NULL, 0, "foobar" );
177 w2 = CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS, NULL );
178 le = GetLastError();
179 ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%u)\n", le );
181 if (w2 != 0)
183 w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS );
184 ok( w3 != 0, "open foobar station failed\n" );
185 ok( w3 != w2, "open foobar station returned same handle\n" );
186 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
187 ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" );
189 w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS );
190 ok( !w3, "open foobar station succeeded\n" );
192 w2 = CreateWindowStationA("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
193 ok( w2 != 0, "create foobar station failed\n" );
194 w3 = CreateWindowStationA("foobar2", 0, WINSTA_ALL_ACCESS, NULL );
195 ok( w3 != 0, "create foobar station failed\n" );
196 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
197 ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" );
199 SetProcessWindowStation( w2 );
200 atom = GlobalAddAtomA("foo");
201 ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
202 ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
204 ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" );
205 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
207 SetProcessWindowStation( w3 );
208 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
209 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
210 ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
211 ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
213 else if (le == ERROR_ACCESS_DENIED)
214 win_skip( "Not enough privileges for CreateWindowStation\n" );
216 SetLastError( 0xdeadbeef );
217 w2 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS );
218 ok( !w2, "open station succeeded\n" );
219 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError() );
221 SetLastError( 0xdeadbeef );
222 w2 = CreateWindowStationA( "", 0, WINSTA_ALL_ACCESS, NULL );
223 ok( w2 != 0, "create station failed err %u\n", GetLastError() );
225 memset( buffer, 0, sizeof(buffer) );
226 ret = GetUserObjectInformationA( w2, UOI_NAME, buffer, sizeof(buffer), &size );
227 ok( ret, "GetUserObjectInformationA failed with error %u\n", GetLastError() );
228 /* Get the logon session LUID */
229 ret = GetTokenInformation( GetCurrentProcessToken(), TokenStatistics, &token_stats, sizeof(token_stats), NULL );
230 if (ret)
231 sprintf( default_name, "Service-0x%x-%x$", token_stats.AuthenticationId.HighPart,
232 token_stats.AuthenticationId.LowPart );
233 if (*default_name)
234 ok( !strcmp( buffer, default_name ), "unexpected window station name '%s' expected '%s'\n", buffer, default_name );
236 SetLastError( 0xdeadbeef );
237 w3 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS );
238 ok( w3 != 0, "open station failed err %u\n", GetLastError() );
239 CloseWindowStation( w3 );
240 CloseWindowStation( w2 );
242 w2 = CreateWindowStationA( NULL, 0, WINSTA_ALL_ACCESS, NULL );
243 ok( w2 != 0, "create station failed err %u\n", GetLastError() );
245 memset( buffer, 0, sizeof(buffer) );
246 ret = GetUserObjectInformationA( w2, UOI_NAME, buffer, sizeof(buffer), &size );
247 ok( ret, "GetUserObjectInformationA failed with error %u\n", GetLastError() );
248 if (*default_name)
249 ok( !strcmp( buffer, default_name ), "unexpected window station name '%s' expected '%s'\n", buffer, default_name );
250 CloseWindowStation( w2 );
252 SetLastError( 0xdeadbeef );
253 w2 = CreateWindowStationA( "foo\\bar", 0, WINSTA_ALL_ACCESS, NULL );
254 ok( !w2, "create station succeeded\n" );
255 ok( GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED,
256 "wrong error %u\n", GetLastError() );
258 SetLastError( 0xdeadbeef );
259 w2 = OpenWindowStationA( "foo\\bar", TRUE, WINSTA_ALL_ACCESS );
260 ok( !w2, "create station succeeded\n" );
261 ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %u\n", GetLastError() );
263 /* desktops */
264 d1 = GetThreadDesktop(GetCurrentThreadId());
265 initial_desktop = d1;
266 ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
267 "GetThreadDesktop returned different handles\n" );
269 flags = 0;
270 ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" );
271 ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 );
273 SetLastError( 0xdeadbeef );
274 ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" );
275 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
276 "bad last error %d\n", GetLastError() );
278 SetLastError( 0xdeadbeef );
279 if (CloseHandle( d1 )) /* succeeds on nt4 */
281 win_skip( "NT4 desktop handle management is completely different\n" );
282 return;
284 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
286 ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
287 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
288 ok( CloseDesktop(d2), "closing dup desktop failed\n" );
290 ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
291 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
292 ok( CloseHandle(d2), "closing dup desktop handle failed\n" );
294 d2 = OpenDesktopA( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
295 ok( !d2, "open dummy desktop succeeded\n" );
297 SetLastError( 0xdeadbeef );
298 d2 = CreateDesktopA( "", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
299 ok( !d2, "create empty desktop succeeded\n" );
300 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
302 SetLastError( 0xdeadbeef );
303 d2 = OpenDesktopA( "", 0, TRUE, DESKTOP_ALL_ACCESS );
304 ok( !d2, "open empty desktop succeeded\n" );
305 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
307 SetLastError( 0xdeadbeef );
308 d2 = CreateDesktopA( "foo\\bar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
309 ok( !d2, "create desktop succeeded\n" );
310 ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() );
312 SetLastError( 0xdeadbeef );
313 d2 = OpenDesktopA( "foo\\bar", 0, TRUE, DESKTOP_ALL_ACCESS );
314 ok( !d2, "open desktop succeeded\n" );
315 ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() );
317 d2 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
318 ok( d2 != 0, "create foobar desktop failed\n" );
319 SetLastError( 0xdeadbeef );
320 ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" );
321 ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */
322 "bad last error %d\n", GetLastError() );
324 SetLastError( 0xdeadbeef );
325 d3 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
326 ok( d3 != 0, "create foobar desktop again failed\n" );
327 ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() );
328 ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
330 d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
331 ok( d3 != 0, "open foobar desktop failed\n" );
332 ok( d3 != d2, "open foobar desktop returned same handle\n" );
333 ok( CloseDesktop( d2 ), "CloseDesktop failed\n" );
334 ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
336 d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
337 ok( !d3, "open foobar desktop succeeded\n" );
339 ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" );
340 d2 = GetThreadDesktop(GetCurrentThreadId());
341 ok( d1 == d2, "got different handles after close\n" );
343 register_class();
344 trace( "thread 1 desktop: %p\n", d1 );
345 print_object( d1 );
346 hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
347 Sleep(1000);
348 trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
349 WaitForSingleObject( hthread, INFINITE );
350 CloseHandle( hthread );
352 /* clean side effect */
353 SetProcessWindowStation( w1 );
356 /* Enumeration tests */
358 static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp)
360 trace("window_station_callbackA called with argument %s\n", winsta);
361 return lp;
364 static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp)
366 HWINSTA hwinsta;
368 trace("open_window_station_callbackA called with argument %s\n", winsta);
369 hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE);
370 ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta);
371 if (hwinsta)
372 CloseWindowStation(hwinsta);
373 return lp;
376 static void test_enumstations(void)
378 DWORD ret;
379 HWINSTA hwinsta;
381 if (0) /* Crashes instead */
383 SetLastError(0xbabefeed);
384 ret = EnumWindowStationsA(NULL, 0);
385 ok(!ret, "EnumWindowStationsA returned successfully!\n");
386 ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
389 hwinsta = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL);
390 ret = GetLastError();
391 ok(hwinsta != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret);
392 if (!hwinsta)
394 win_skip("Not enough privileges for CreateWindowStation\n");
395 return;
398 SetLastError(0xdeadbeef);
399 ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345);
400 ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret);
401 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
403 SetLastError(0xdeadbeef);
404 ret = EnumWindowStationsA(window_station_callbackA, 0);
405 ok(!ret, "EnumWindowStationsA returned %x\n", ret);
406 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
409 static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp)
411 trace("desktop_callbackA called with argument %s\n", desktop);
412 return lp;
415 static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp)
417 HDESK hdesk;
418 static int once;
420 trace("open_desktop_callbackA called with argument %s\n", desktop);
421 /* Only try to open one desktop */
422 if (once++)
423 return lp;
425 hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE);
426 ok(hdesk != NULL, "Could not open desktop %s!\n", desktop);
427 if (hdesk)
428 CloseDesktop(hdesk);
429 return lp;
432 static void test_enumdesktops(void)
434 BOOL ret;
436 if (0) /* Crashes instead */
438 SetLastError(0xbabefeed);
439 ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0);
440 ok(!ret, "EnumDesktopsA returned successfully!\n");
441 ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
444 SetLastError(0xdeadbeef);
445 ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345);
446 ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
447 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
449 SetLastError(0xdeadbeef);
450 ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345);
451 ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
452 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
454 SetLastError(0xdeadbeef);
455 ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345);
456 ok(!ret, "EnumDesktopsA returned %x\n", ret);
457 ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError());
459 SetLastError(0xdeadbeef);
460 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
461 ok(!ret, "EnumDesktopsA returned %x\n", ret);
462 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
465 /* Miscellaneous tests */
467 static void test_getuserobjectinformation(void)
469 WCHAR foobarTestW[] = {'\\','f','o','o','b','a','r','T','e','s','t',0};
470 WCHAR DesktopW[] = {'D','e','s','k','t','o','p',0};
471 OBJECT_NAME_INFORMATION *name_info;
472 WCHAR bufferW[20];
473 char buffer[64];
474 NTSTATUS status;
475 DWORD size;
476 HDESK desk;
477 BOOL ret;
479 desk = CreateDesktopA("foobarTest", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
480 ok(desk != 0, "open foobarTest desktop failed\n");
482 strcpy(buffer, "blahblah");
484 /** Tests for UOI_NAME **/
486 /* Get size, test size and return value/error code */
487 SetLastError(0xdeadbeef);
488 size = 0xdeadbeef;
489 ret = GetUserObjectInformationA(desk, UOI_NAME, NULL, 0, &size);
491 ok(!ret, "GetUserObjectInformationA returned %x\n", ret);
492 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
493 ok(size == 22, "size is set to %d\n", size); /* Windows returns Unicode length (11*2) */
495 /* Get string */
496 SetLastError(0xdeadbeef);
497 size = 0xdeadbeef;
498 ret = GetUserObjectInformationA(desk, UOI_NAME, buffer, sizeof(buffer), &size);
500 ok(ret, "GetUserObjectInformationA returned %x\n", ret);
501 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
503 ok(strcmp(buffer, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer);
504 ok(size == 11, "size is set to %d\n", size); /* 11 bytes in 'foobarTest\0' */
506 /* Get size, test size and return value/error code (Unicode) */
507 SetLastError(0xdeadbeef);
508 size = 0xdeadbeef;
509 ret = GetUserObjectInformationW(desk, UOI_NAME, NULL, 0, &size);
511 ok(!ret, "GetUserObjectInformationW returned %x\n", ret);
512 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
513 ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */
515 /* Get string (Unicode) */
516 SetLastError(0xdeadbeef);
517 size = 0xdeadbeef;
518 ret = GetUserObjectInformationW(desk, UOI_NAME, bufferW, sizeof(bufferW), &size);
520 ok(ret, "GetUserObjectInformationW returned %x\n", ret);
521 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
523 ok(lstrcmpW(bufferW, foobarTestW + 1) == 0, "Buffer is not set to 'foobarTest'\n");
524 ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */
526 /* ObjectNameInformation does not return the full desktop name */
527 name_info = (OBJECT_NAME_INFORMATION *)buffer;
528 status = pNtQueryObject(desk, ObjectNameInformation, name_info, sizeof(buffer), NULL);
529 ok(!status, "expected STATUS_SUCCESS, got %08x\n", status);
530 ok(lstrcmpW(name_info->Name.Buffer, foobarTestW) == 0,
531 "expected '\\foobarTest', got %s\n", wine_dbgstr_w(name_info->Name.Buffer));
533 /** Tests for UOI_TYPE **/
535 /* Get size, test size and return value/error code */
536 SetLastError(0xdeadbeef);
537 size = 0xdeadbeef;
538 ret = GetUserObjectInformationA(desk, UOI_TYPE, NULL, 0, &size);
540 ok(!ret, "GetUserObjectInformationA returned %x\n", ret);
541 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
542 ok(size == 16, "size is set to %d\n", size); /* Windows returns Unicode length (8*2) */
544 /* Get string */
545 SetLastError(0xdeadbeef);
546 size = 0xdeadbeef;
547 ret = GetUserObjectInformationA(desk, UOI_TYPE, buffer, sizeof(buffer), &size);
549 ok(ret, "GetUserObjectInformationA returned %x\n", ret);
550 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
552 ok(strcmp(buffer, "Desktop") == 0, "Buffer is set to '%s'\n", buffer);
553 ok(size == 8, "size is set to %d\n", size); /* 8 bytes in 'Desktop\0' */
555 /* Get size, test size and return value/error code (Unicode) */
556 size = 0xdeadbeef;
557 SetLastError(0xdeadbeef);
558 ret = GetUserObjectInformationW(desk, UOI_TYPE, NULL, 0, &size);
560 ok(!ret, "GetUserObjectInformationW returned %x\n", ret);
561 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
562 ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */
564 /* Get string (Unicode) */
565 SetLastError(0xdeadbeef);
566 size = 0xdeadbeef;
567 ret = GetUserObjectInformationW(desk, UOI_TYPE, bufferW, sizeof(bufferW), &size);
569 ok(ret, "GetUserObjectInformationW returned %x\n", ret);
570 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
572 ok(lstrcmpW(bufferW, DesktopW) == 0, "Buffer is not set to 'Desktop'\n");
573 ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */
575 ok(CloseDesktop(desk), "CloseDesktop failed\n");
578 static void test_inputdesktop(void)
580 HDESK input_desk, old_input_desk, thread_desk, old_thread_desk, new_desk;
581 DWORD ret;
582 CHAR name[1024];
583 INPUT inputs[1];
585 inputs[0].type = INPUT_KEYBOARD;
586 U(inputs[0]).ki.wVk = 0;
587 U(inputs[0]).ki.wScan = 0x3c0;
588 U(inputs[0]).ki.dwFlags = KEYEVENTF_UNICODE;
590 /* OpenInputDesktop creates new handles for each calls */
591 old_input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
592 ok(old_input_desk != NULL, "OpenInputDesktop failed!\n");
593 memset(name, 0, sizeof(name));
594 ret = GetUserObjectInformationA(old_input_desk, UOI_NAME, name, 1024, NULL);
595 ok(ret, "GetUserObjectInformation failed!\n");
596 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
598 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
599 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
600 memset(name, 0, sizeof(name));
601 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
602 ok(ret, "GetUserObjectInformation failed!\n");
603 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
605 ok(old_input_desk != input_desk, "returned the same handle!\n");
606 ret = CloseDesktop(input_desk);
607 ok(ret, "CloseDesktop failed!\n");
609 /* by default, GetThreadDesktop is the input desktop, SendInput should succeed. */
610 old_thread_desk = GetThreadDesktop(GetCurrentThreadId());
611 ok(old_thread_desk != NULL, "GetThreadDesktop failed!\n");
612 memset(name, 0, sizeof(name));
613 ret = GetUserObjectInformationA(old_thread_desk, UOI_NAME, name, 1024, NULL);
614 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
616 SetLastError(0xdeadbeef);
617 ret = SendInput(1, inputs, sizeof(INPUT));
618 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
619 ok(ret == 1, "unexpected return count %d\n", ret);
621 /* Set thread desktop to the new desktop, SendInput should fail. */
622 new_desk = CreateDesktopA("new_desk", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
623 ok(new_desk != NULL, "CreateDesktop failed!\n");
624 ret = SetThreadDesktop(new_desk);
625 ok(ret, "SetThreadDesktop failed!\n");
626 thread_desk = GetThreadDesktop(GetCurrentThreadId());
627 ok(thread_desk == new_desk, "thread desktop doesn't match!\n");
628 memset(name, 0, sizeof(name));
629 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
630 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
632 SetLastError(0xdeadbeef);
633 ret = SendInput(1, inputs, sizeof(INPUT));
634 if(broken(GetLastError() == 0xdeadbeef))
636 SetThreadDesktop(old_thread_desk);
637 CloseDesktop(old_input_desk);
638 CloseDesktop(input_desk);
639 CloseDesktop(new_desk);
640 win_skip("Skip tests on NT4\n");
641 return;
643 todo_wine
644 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError());
645 ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret);
647 /* Set thread desktop back to the old thread desktop, SendInput should success. */
648 ret = SetThreadDesktop(old_thread_desk);
649 ok(ret, "SetThreadDesktop failed!\n");
650 thread_desk = GetThreadDesktop(GetCurrentThreadId());
651 ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n");
652 memset(name, 0, sizeof(name));
653 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
654 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
656 SetLastError(0xdeadbeef);
657 ret = SendInput(1, inputs, sizeof(INPUT));
658 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
659 ok(ret == 1, "unexpected return count %d\n", ret);
661 /* Set thread desktop to the input desktop, SendInput should success. */
662 ret = SetThreadDesktop(old_input_desk);
663 ok(ret, "SetThreadDesktop failed!\n");
664 thread_desk = GetThreadDesktop(GetCurrentThreadId());
665 ok(thread_desk == old_input_desk, "thread desktop doesn't match!\n");
666 memset(name, 0, sizeof(name));
667 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
668 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
670 SetLastError(0xdeadbeef);
671 ret = SendInput(1, inputs, sizeof(INPUT));
672 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
673 ok(ret == 1, "unexpected return count %d\n", ret);
675 /* Switch input desktop to the new desktop, SendInput should fail. */
676 ret = SwitchDesktop(new_desk);
677 ok(ret, "SwitchDesktop failed!\n");
678 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
679 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
680 ok(input_desk != new_desk, "returned the same handle!\n");
681 memset(name, 0, sizeof(name));
682 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
683 ok(ret, "GetUserObjectInformation failed!\n");
684 todo_wine
685 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
686 ret = CloseDesktop(input_desk);
687 ok(ret, "CloseDesktop failed!\n");
689 SetLastError(0xdeadbeef);
690 ret = SendInput(1, inputs, sizeof(INPUT));
691 todo_wine
692 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError());
693 ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret);
695 /* Set thread desktop to the new desktop, SendInput should success. */
696 ret = SetThreadDesktop(new_desk);
697 ok(ret, "SetThreadDesktop failed!\n");
698 thread_desk = GetThreadDesktop(GetCurrentThreadId());
699 ok(thread_desk == new_desk, "thread desktop doesn't match!\n");
700 memset(name, 0, sizeof(name));
701 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
702 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
704 SetLastError(0xdeadbeef);
705 ret = SendInput(1, inputs, sizeof(INPUT));
706 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
707 ok(ret == 1, "unexpected return count %d\n", ret);
709 /* Switch input desktop to the old input desktop, set thread desktop to the old
710 * thread desktop, clean side effects. SendInput should success. */
711 ret = SwitchDesktop(old_input_desk);
712 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
713 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
714 ok(input_desk != old_input_desk, "returned the same handle!\n");
715 memset(name, 0, sizeof(name));
716 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
717 ok(ret, "GetUserObjectInformation failed!\n");
718 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
720 ret = SetThreadDesktop(old_thread_desk);
721 ok(ret, "SetThreadDesktop failed!\n");
722 thread_desk = GetThreadDesktop(GetCurrentThreadId());
723 ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n");
724 memset(name, 0, sizeof(name));
725 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
726 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
728 SetLastError(0xdeadbeef);
729 ret = SendInput(1, inputs, sizeof(INPUT));
730 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
731 ok(ret == 1, "unexpected return count %d\n", ret);
733 /* free resources */
734 ret = CloseDesktop(input_desk);
735 ok(ret, "CloseDesktop failed!\n");
736 ret = CloseDesktop(old_input_desk);
737 ok(ret, "CloseDesktop failed!\n");
738 ret = CloseDesktop(new_desk);
739 ok(ret, "CloseDesktop failed!\n");
742 static void test_inputdesktop2(void)
744 HWINSTA w1, w2;
745 HDESK thread_desk, new_desk, input_desk, hdesk;
746 DWORD ret;
748 thread_desk = GetThreadDesktop(GetCurrentThreadId());
749 ok(thread_desk != NULL, "GetThreadDesktop failed!\n");
750 w1 = GetProcessWindowStation();
751 ok(w1 != NULL, "GetProcessWindowStation failed!\n");
752 SetLastError(0xdeadbeef);
753 w2 = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL);
754 ret = GetLastError();
755 ok(w2 != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret);
756 if (!w2)
758 win_skip("Not enough privileges for CreateWindowStation\n");
759 return;
762 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
763 ok(!ret, "EnumDesktopsA failed!\n");
764 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
765 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
766 ret = CloseDesktop(input_desk);
767 ok(ret, "CloseDesktop failed!\n");
769 ret = SetProcessWindowStation(w2);
770 ok(ret, "SetProcessWindowStation failed!\n");
771 hdesk = GetThreadDesktop(GetCurrentThreadId());
772 ok(hdesk != NULL, "GetThreadDesktop failed!\n");
773 ok(hdesk == thread_desk, "thread desktop should not change after winstation changed!\n");
774 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
776 new_desk = CreateDesktopA("desk_test", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
777 ok(new_desk != NULL, "CreateDesktop failed!\n");
778 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
779 ok(!ret, "EnumDesktopsA failed!\n");
780 SetLastError(0xdeadbeef);
781 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
782 ok(input_desk == NULL, "OpenInputDesktop should fail on non default winstation!\n");
783 ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
785 hdesk = OpenDesktopA("desk_test", 0, TRUE, DESKTOP_ALL_ACCESS);
786 ok(hdesk != NULL, "OpenDesktop failed!\n");
787 SetLastError(0xdeadbeef);
788 ret = SwitchDesktop(hdesk);
789 todo_wine
790 ok(!ret, "Switch to desktop belong to non default winstation should fail!\n");
791 todo_wine
792 ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
793 ret = SetThreadDesktop(hdesk);
794 ok(ret, "SetThreadDesktop failed!\n");
796 /* clean side effect */
797 ret = SetThreadDesktop(thread_desk);
798 todo_wine
799 ok(ret, "SetThreadDesktop should success even desktop is not belong to process winstation!\n");
800 ret = SetProcessWindowStation(w1);
801 ok(ret, "SetProcessWindowStation failed!\n");
802 ret = SetThreadDesktop(thread_desk);
803 ok(ret, "SetThreadDesktop failed!\n");
804 ret = CloseWindowStation(w2);
805 ok(ret, "CloseWindowStation failed!\n");
806 ret = CloseDesktop(new_desk);
807 ok(ret, "CloseDesktop failed!\n");
808 ret = CloseDesktop(hdesk);
809 ok(ret, "CloseDesktop failed!\n");
812 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
814 if (msg == WM_DESTROY)
816 trace("destroying hwnd %p\n", hWnd);
817 PostQuitMessage(0);
818 return 0;
820 return DefWindowProcA( hWnd, msg, wParam, lParam );
823 typedef struct tag_wnd_param
825 const char *wnd_name;
826 HWND hwnd;
827 HDESK hdesk;
828 HANDLE hevent;
829 } wnd_param;
831 static DWORD WINAPI create_window(LPVOID param)
833 wnd_param *param1 = param;
834 DWORD ret;
835 MSG msg;
837 ret = SetThreadDesktop(param1->hdesk);
838 ok(ret, "SetThreadDesktop failed!\n");
839 param1->hwnd = CreateWindowA("test_class", param1->wnd_name, WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
840 ok(param1->hwnd != 0, "CreateWindowA failed!\n");
841 ret = SetEvent(param1->hevent);
842 ok(ret, "SetEvent failed!\n");
844 while (GetMessageA(&msg, 0, 0, 0))
846 TranslateMessage(&msg);
847 DispatchMessageA(&msg);
850 return 0;
853 static DWORD set_foreground(HWND hwnd)
855 HWND hwnd_fore;
856 DWORD set_id, fore_id, ret;
857 char win_text[1024];
859 hwnd_fore = GetForegroundWindow();
860 GetWindowTextA(hwnd_fore, win_text, 1024);
861 set_id = GetWindowThreadProcessId(hwnd, NULL);
862 fore_id = GetWindowThreadProcessId(hwnd_fore, NULL);
863 trace("\"%s\" %p %08x hwnd %p %08x\n", win_text, hwnd_fore, fore_id, hwnd, set_id);
864 ret = AttachThreadInput(set_id, fore_id, TRUE);
865 trace("AttachThreadInput returned %08x\n", ret);
866 ret = ShowWindow(hwnd, SW_SHOWNORMAL);
867 trace("ShowWindow returned %08x\n", ret);
868 ret = SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
869 trace("set topmost returned %08x\n", ret);
870 ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
871 trace("set notopmost returned %08x\n", ret);
872 ret = SetForegroundWindow(hwnd);
873 trace("SetForegroundWindow returned %08x\n", ret);
874 Sleep(250);
875 AttachThreadInput(set_id, fore_id, FALSE);
876 return ret;
879 static void test_foregroundwindow(void)
881 HWND hwnd, hwnd_test, partners[2], hwnds[2];
882 HDESK hdesks[2];
883 int thread_desk_id, input_desk_id, hwnd_id;
884 WNDCLASSA wclass;
885 wnd_param param;
886 DWORD ret, timeout, timeout_old;
887 char win_text[1024];
889 #define DESKTOPS 2
891 memset( &wclass, 0, sizeof(wclass) );
892 wclass.lpszClassName = "test_class";
893 wclass.lpfnWndProc = WndProc;
894 RegisterClassA(&wclass);
895 param.wnd_name = "win_name";
897 hdesks[0] = GetThreadDesktop(GetCurrentThreadId());
898 ok(hdesks[0] != NULL, "OpenDesktop failed!\n");
899 SetLastError(0xdeadbeef);
900 hdesks[1] = CreateDesktopA("desk2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
901 ret = GetLastError();
902 ok(hdesks[1] != NULL || ret == ERROR_ACCESS_DENIED, "CreateDesktop failed (%u)\n", ret);
903 if(!hdesks[1])
905 win_skip("Not enough privileges for CreateDesktop\n");
906 return;
909 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout_old, 0);
910 if(!ret)
912 win_skip("Skip tests on NT4\n");
913 CloseDesktop(hdesks[1]);
914 return;
916 trace("old timeout %d\n", timeout_old);
917 timeout = 0;
918 ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
919 ok(ret, "set foreground lock timeout failed!\n");
920 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0);
921 ok(ret, "get foreground lock timeout failed!\n");
922 ok(timeout == 0, "unexpected timeout %d\n", timeout);
924 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
926 param.hdesk = hdesks[thread_desk_id];
927 param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL);
928 CreateThread(NULL, 0, create_window, &param, 0, NULL);
929 ret = WaitForSingleObject(param.hevent, INFINITE);
930 ok(ret == WAIT_OBJECT_0, "wait failed!\n");
931 hwnds[thread_desk_id] = param.hwnd;
934 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
936 param.hdesk = hdesks[thread_desk_id];
937 param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL);
938 CreateThread(NULL, 0, create_window, &param, 0, NULL);
939 ret = WaitForSingleObject(param.hevent, INFINITE);
940 ok(ret == WAIT_OBJECT_0, "wait failed!\n");
941 partners[thread_desk_id] = param.hwnd;
944 trace("hwnd0 %p hwnd1 %p partner0 %p partner1 %p\n", hwnds[0], hwnds[1], partners[0], partners[1]);
946 for (hwnd_id = 0; hwnd_id < DESKTOPS; hwnd_id++)
947 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
948 for (input_desk_id = 0; input_desk_id < DESKTOPS; input_desk_id++)
950 trace("testing thread_desk %d input_desk %d hwnd %d\n",
951 thread_desk_id, input_desk_id, hwnd_id);
952 hwnd_test = hwnds[hwnd_id];
953 ret = SetThreadDesktop(hdesks[thread_desk_id]);
954 ok(ret, "set thread desktop failed!\n");
955 ret = SwitchDesktop(hdesks[input_desk_id]);
956 ok(ret, "switch desktop failed!\n");
957 set_foreground(partners[0]);
958 set_foreground(partners[1]);
959 hwnd = GetForegroundWindow();
960 ok(hwnd != hwnd_test, "unexpected foreground window %p\n", hwnd);
961 ret = set_foreground(hwnd_test);
962 hwnd = GetForegroundWindow();
963 GetWindowTextA(hwnd, win_text, 1024);
964 trace("hwnd %p name %s\n", hwnd, win_text);
965 if (input_desk_id == hwnd_id)
967 if (input_desk_id == thread_desk_id)
969 ok(ret, "SetForegroundWindow failed!\n");
970 todo_wine_if (!hwnd)
971 ok(hwnd == hwnd_test , "unexpected foreground window %p\n", hwnd);
973 else
975 todo_wine ok(ret, "SetForegroundWindow failed!\n");
976 todo_wine ok(hwnd == 0, "unexpected foreground window %p\n", hwnd);
979 else
981 if (input_desk_id == thread_desk_id)
983 ok(!ret, "SetForegroundWindow should fail!\n");
984 todo_wine_if (!hwnd)
985 ok(hwnd == partners[input_desk_id] , "unexpected foreground window %p\n", hwnd);
987 else
989 todo_wine ok(!ret, "SetForegroundWindow should fail!\n");
990 todo_wine_if (hwnd)
991 ok(hwnd == 0, "unexpected foreground window %p\n", hwnd);
996 /* Clean up */
998 for (thread_desk_id = DESKTOPS - 1; thread_desk_id >= 0; thread_desk_id--)
1000 ret = SetThreadDesktop(hdesks[thread_desk_id]);
1001 ok(ret, "set thread desktop failed!\n");
1002 SendMessageA(hwnds[thread_desk_id], WM_DESTROY, 0, 0);
1003 SendMessageA(partners[thread_desk_id], WM_DESTROY, 0, 0);
1006 ret = SwitchDesktop(hdesks[0]);
1007 ok(ret, "switch desktop failed!\n");
1008 CloseDesktop(hdesks[1]);
1010 ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UlongToPtr(timeout_old), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1011 ok(ret, "set foreground lock timeout failed!\n");
1012 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0);
1013 ok(ret, "get foreground lock timeout failed!\n");
1014 ok(timeout == timeout_old, "unexpected timeout %d\n", timeout);
1017 START_TEST(winstation)
1019 HMODULE hntdll = GetModuleHandleA("ntdll.dll");
1020 pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject");
1022 /* Check whether this platform supports WindowStation calls */
1024 SetLastError( 0xdeadbeef );
1025 GetProcessWindowStation();
1026 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1028 win_skip("WindowStation calls not supported on this platform\n");
1029 return;
1032 test_inputdesktop();
1033 test_inputdesktop2();
1034 test_enumstations();
1035 test_enumdesktops();
1036 test_handles();
1037 test_getuserobjectinformation();
1038 test_foregroundwindow();