3e0fe936b52af8059c678da11cc101095546075c
[reactos.git] / modules / rostests / winetests / user32 / winstation.c
1 /*
2 * Unit tests for window stations and desktops
3 *
4 * Copyright 2002 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22
23 #include <wine/winternl.h>
24
25 static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
26
27 #define DESKTOP_ALL_ACCESS 0x01ff
28
29 static void print_object( HANDLE obj )
30 {
31 char buffer[100];
32 DWORD size;
33
34 strcpy( buffer, "foobar" );
35 if (!GetUserObjectInformationA( obj, UOI_NAME, buffer, sizeof(buffer), &size ))
36 trace( "could not get info for %p\n", obj );
37 else
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 );
42 else
43 trace( "obj %p type '%s'\n", obj, buffer );
44 }
45
46 static void register_class(void)
47 {
48 WNDCLASSA cls;
49
50 cls.style = CS_DBLCLKS;
51 cls.lpfnWndProc = DefWindowProcA;
52 cls.cbClsExtra = 0;
53 cls.cbWndExtra = 0;
54 cls.hInstance = GetModuleHandleA(0);
55 cls.hIcon = 0;
56 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
57 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
58 cls.lpszMenuName = NULL;
59 cls.lpszClassName = "WinStationClass";
60 RegisterClassA(&cls);
61 }
62
63 static HDESK initial_desktop;
64
65 static DWORD CALLBACK thread( LPVOID arg )
66 {
67 HDESK d1, d2;
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 );
73
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() );
81 print_object( d1 );
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" );
85
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() );
90
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 );
95 print_object( d2 );
96 if (arg < (LPVOID)5)
97 {
98 HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL );
99 Sleep(1000);
100 WaitForSingleObject( hthread, INFINITE );
101 CloseHandle( hthread );
102 }
103 return 0;
104 }
105
106 static void test_handles(void)
107 {
108 HWINSTA w1, w2, w3;
109 HDESK d1, d2, d3;
110 HANDLE hthread;
111 DWORD id, flags, le;
112 ATOM atom;
113 char buffer[20];
114 DWORD size;
115 BOOL ret;
116
117 /* win stations */
118
119 w1 = GetProcessWindowStation();
120 ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" );
121 ok( !CloseWindowStation(w1), "closing process win station succeeded\n" );
122 SetLastError( 0xdeadbeef );
123 ok( !CloseHandle(w1), "closing process win station handle succeeded\n" );
124 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
125 print_object( w1 );
126
127 flags = 0;
128 ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
129 ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ||
130 broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */
131 "handle %p PROTECT_FROM_CLOSE set\n", w1 );
132
133 ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
134 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
135 ok( CloseWindowStation(w2), "closing dup win station failed\n" );
136
137 ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
138 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
139 ok( CloseHandle(w2), "closing dup win station handle failed\n" );
140
141 w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
142 le = GetLastError();
143 ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", le );
144 if (w2 != 0)
145 {
146 ok( w2 != w1, "CreateWindowStation returned default handle\n" );
147 SetLastError( 0xdeadbeef );
148 ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" );
149 ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */
150 "bad last error %d\n", GetLastError() );
151 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
152
153 w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
154 ok( CloseHandle( w2 ), "CloseHandle failed\n" );
155 }
156 else if (le == ERROR_ACCESS_DENIED)
157 win_skip( "Not enough privileges for CreateWindowStation\n" );
158
159 w2 = OpenWindowStationA("winsta0", TRUE, WINSTA_ALL_ACCESS );
160 ok( w2 != 0, "OpenWindowStation failed\n" );
161 ok( w2 != w1, "OpenWindowStation returned default handle\n" );
162 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
163
164 w2 = OpenWindowStationA("dummy name", TRUE, WINSTA_ALL_ACCESS );
165 ok( !w2, "open dummy win station succeeded\n" );
166
167 CreateMutexA( NULL, 0, "foobar" );
168 w2 = CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS, NULL );
169 le = GetLastError();
170 ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%u)\n", le );
171
172 if (w2 != 0)
173 {
174 w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS );
175 ok( w3 != 0, "open foobar station failed\n" );
176 ok( w3 != w2, "open foobar station returned same handle\n" );
177 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
178 ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" );
179
180 w3 = OpenWindowStationA("foobar", TRUE, WINSTA_ALL_ACCESS );
181 ok( !w3, "open foobar station succeeded\n" );
182
183 w2 = CreateWindowStationA("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
184 ok( w2 != 0, "create foobar station failed\n" );
185 w3 = CreateWindowStationA("foobar2", 0, WINSTA_ALL_ACCESS, NULL );
186 ok( w3 != 0, "create foobar station failed\n" );
187 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
188 ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" );
189
190 SetProcessWindowStation( w2 );
191 atom = GlobalAddAtomA("foo");
192 ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
193 ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
194
195 ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" );
196 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
197
198 SetProcessWindowStation( w3 );
199 ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
200 ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
201 ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
202 ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
203 }
204 else if (le == ERROR_ACCESS_DENIED)
205 win_skip( "Not enough privileges for CreateWindowStation\n" );
206
207 SetLastError( 0xdeadbeef );
208 w2 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS );
209 ok( !w2, "open station succeeded\n" );
210 todo_wine
211 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError() );
212
213 SetLastError( 0xdeadbeef );
214 w2 = CreateWindowStationA( "", 0, WINSTA_ALL_ACCESS, NULL );
215 ok( w2 != 0, "create station failed err %u\n", GetLastError() );
216
217 memset( buffer, 0, sizeof(buffer) );
218 ret = GetUserObjectInformationA( w2, UOI_NAME, buffer, sizeof(buffer), &size );
219 ok( ret, "GetUserObjectInformationA failed with error %u\n", GetLastError() );
220 ok( !memcmp(buffer, "Service-0x0-", 12), "unexpected window station name '%s'\n", buffer );
221 ok( buffer[strlen(buffer) - 1] == '$', "unexpected window station name '%s'\n", buffer );
222
223 SetLastError( 0xdeadbeef );
224 w3 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS );
225 todo_wine
226 ok( w3 != 0, "open station failed err %u\n", GetLastError() );
227 CloseWindowStation( w3 );
228 CloseWindowStation( w2 );
229
230 SetLastError( 0xdeadbeef );
231 w2 = CreateWindowStationA( "foo\\bar", 0, WINSTA_ALL_ACCESS, NULL );
232 ok( !w2, "create station succeeded\n" );
233 ok( GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED,
234 "wrong error %u\n", GetLastError() );
235
236 SetLastError( 0xdeadbeef );
237 w2 = OpenWindowStationA( "foo\\bar", TRUE, WINSTA_ALL_ACCESS );
238 ok( !w2, "create station succeeded\n" );
239 ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %u\n", GetLastError() );
240
241 /* desktops */
242 d1 = GetThreadDesktop(GetCurrentThreadId());
243 initial_desktop = d1;
244 ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
245 "GetThreadDesktop returned different handles\n" );
246
247 flags = 0;
248 ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" );
249 ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 );
250
251 SetLastError( 0xdeadbeef );
252 ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" );
253 ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */
254 "bad last error %d\n", GetLastError() );
255
256 SetLastError( 0xdeadbeef );
257 if (CloseHandle( d1 )) /* succeeds on nt4 */
258 {
259 win_skip( "NT4 desktop handle management is completely different\n" );
260 return;
261 }
262 ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
263
264 ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
265 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
266 ok( CloseDesktop(d2), "closing dup desktop failed\n" );
267
268 ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
269 TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
270 ok( CloseHandle(d2), "closing dup desktop handle failed\n" );
271
272 d2 = OpenDesktopA( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
273 ok( !d2, "open dummy desktop succeeded\n" );
274
275 SetLastError( 0xdeadbeef );
276 d2 = CreateDesktopA( "", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
277 todo_wine
278 ok( !d2, "create empty desktop succeeded\n" );
279 todo_wine
280 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
281
282 SetLastError( 0xdeadbeef );
283 d2 = OpenDesktopA( "", 0, TRUE, DESKTOP_ALL_ACCESS );
284 ok( !d2, "open empty desktop succeeded\n" );
285 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
286
287 SetLastError( 0xdeadbeef );
288 d2 = CreateDesktopA( "foo\\bar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
289 ok( !d2, "create desktop succeeded\n" );
290 ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() );
291
292 SetLastError( 0xdeadbeef );
293 d2 = OpenDesktopA( "foo\\bar", 0, TRUE, DESKTOP_ALL_ACCESS );
294 ok( !d2, "open desktop succeeded\n" );
295 ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() );
296
297 d2 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
298 ok( d2 != 0, "create foobar desktop failed\n" );
299 SetLastError( 0xdeadbeef );
300 ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" );
301 ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */
302 "bad last error %d\n", GetLastError() );
303
304 SetLastError( 0xdeadbeef );
305 d3 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
306 ok( d3 != 0, "create foobar desktop again failed\n" );
307 ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() );
308 ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
309
310 d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
311 ok( d3 != 0, "open foobar desktop failed\n" );
312 ok( d3 != d2, "open foobar desktop returned same handle\n" );
313 ok( CloseDesktop( d2 ), "CloseDesktop failed\n" );
314 ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
315
316 d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
317 ok( !d3, "open foobar desktop succeeded\n" );
318
319 ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" );
320 d2 = GetThreadDesktop(GetCurrentThreadId());
321 ok( d1 == d2, "got different handles after close\n" );
322
323 register_class();
324 trace( "thread 1 desktop: %p\n", d1 );
325 print_object( d1 );
326 hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
327 Sleep(1000);
328 trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
329 WaitForSingleObject( hthread, INFINITE );
330 CloseHandle( hthread );
331
332 /* clean side effect */
333 SetProcessWindowStation( w1 );
334 }
335
336 /* Enumeration tests */
337
338 static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp)
339 {
340 trace("window_station_callbackA called with argument %s\n", winsta);
341 return lp;
342 }
343
344 static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp)
345 {
346 HWINSTA hwinsta;
347
348 trace("open_window_station_callbackA called with argument %s\n", winsta);
349 hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE);
350 ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta);
351 if (hwinsta)
352 CloseWindowStation(hwinsta);
353 return lp;
354 }
355
356 static void test_enumstations(void)
357 {
358 DWORD ret;
359 HWINSTA hwinsta;
360
361 if (0) /* Crashes instead */
362 {
363 SetLastError(0xbabefeed);
364 ret = EnumWindowStationsA(NULL, 0);
365 ok(!ret, "EnumWindowStationsA returned successfully!\n");
366 ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
367 }
368
369 hwinsta = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL);
370 ret = GetLastError();
371 ok(hwinsta != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret);
372 if (!hwinsta)
373 {
374 win_skip("Not enough privileges for CreateWindowStation\n");
375 return;
376 }
377
378 SetLastError(0xdeadbeef);
379 ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345);
380 ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret);
381 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
382
383 SetLastError(0xdeadbeef);
384 ret = EnumWindowStationsA(window_station_callbackA, 0);
385 ok(!ret, "EnumWindowStationsA returned %x\n", ret);
386 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
387 }
388
389 static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp)
390 {
391 trace("desktop_callbackA called with argument %s\n", desktop);
392 return lp;
393 }
394
395 static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp)
396 {
397 HDESK hdesk;
398 static int once;
399
400 trace("open_desktop_callbackA called with argument %s\n", desktop);
401 /* Only try to open one desktop */
402 if (once++)
403 return lp;
404
405 hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE);
406 ok(hdesk != NULL, "Could not open desktop %s!\n", desktop);
407 if (hdesk)
408 CloseDesktop(hdesk);
409 return lp;
410 }
411
412 static void test_enumdesktops(void)
413 {
414 BOOL ret;
415
416 if (0) /* Crashes instead */
417 {
418 SetLastError(0xbabefeed);
419 ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0);
420 ok(!ret, "EnumDesktopsA returned successfully!\n");
421 ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
422 }
423
424 SetLastError(0xdeadbeef);
425 ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345);
426 ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
427 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
428
429 SetLastError(0xdeadbeef);
430 ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345);
431 ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
432 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
433
434 SetLastError(0xdeadbeef);
435 ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345);
436 ok(!ret, "EnumDesktopsA returned %x\n", ret);
437 ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError());
438
439 SetLastError(0xdeadbeef);
440 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
441 ok(!ret, "EnumDesktopsA returned %x\n", ret);
442 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
443 }
444
445 /* Miscellaneous tests */
446
447 static void test_getuserobjectinformation(void)
448 {
449 WCHAR foobarTestW[] = {'\\','f','o','o','b','a','r','T','e','s','t',0};
450 WCHAR DesktopW[] = {'D','e','s','k','t','o','p',0};
451 OBJECT_NAME_INFORMATION *name_info;
452 WCHAR bufferW[20];
453 char buffer[64];
454 NTSTATUS status;
455 DWORD size;
456 HDESK desk;
457 BOOL ret;
458
459 desk = CreateDesktopA("foobarTest", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
460 ok(desk != 0, "open foobarTest desktop failed\n");
461
462 strcpy(buffer, "blahblah");
463
464 /** Tests for UOI_NAME **/
465
466 /* Get size, test size and return value/error code */
467 SetLastError(0xdeadbeef);
468 size = 0xdeadbeef;
469 ret = GetUserObjectInformationA(desk, UOI_NAME, NULL, 0, &size);
470
471 ok(!ret, "GetUserObjectInformationA returned %x\n", ret);
472 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
473 ok(size == 22, "size is set to %d\n", size); /* Windows returns Unicode length (11*2) */
474
475 /* Get string */
476 SetLastError(0xdeadbeef);
477 size = 0xdeadbeef;
478 ret = GetUserObjectInformationA(desk, UOI_NAME, buffer, sizeof(buffer), &size);
479
480 ok(ret, "GetUserObjectInformationA returned %x\n", ret);
481 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
482
483 ok(strcmp(buffer, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer);
484 ok(size == 11, "size is set to %d\n", size); /* 11 bytes in 'foobarTest\0' */
485
486 /* Get size, test size and return value/error code (Unicode) */
487 SetLastError(0xdeadbeef);
488 size = 0xdeadbeef;
489 ret = GetUserObjectInformationW(desk, UOI_NAME, NULL, 0, &size);
490
491 ok(!ret, "GetUserObjectInformationW 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); /* 22 bytes in 'foobarTest\0' in Unicode */
494
495 /* Get string (Unicode) */
496 SetLastError(0xdeadbeef);
497 size = 0xdeadbeef;
498 ret = GetUserObjectInformationW(desk, UOI_NAME, bufferW, sizeof(bufferW), &size);
499
500 ok(ret, "GetUserObjectInformationW returned %x\n", ret);
501 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
502
503 ok(lstrcmpW(bufferW, foobarTestW + 1) == 0, "Buffer is not set to 'foobarTest'\n");
504 ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */
505
506 /* ObjectNameInformation does not return the full desktop name */
507 name_info = (OBJECT_NAME_INFORMATION *)buffer;
508 status = pNtQueryObject(desk, ObjectNameInformation, name_info, sizeof(buffer), NULL);
509 ok(!status, "expected STATUS_SUCCESS, got %08x\n", status);
510 ok(lstrcmpW(name_info->Name.Buffer, foobarTestW) == 0,
511 "expected '\\foobarTest', got %s\n", wine_dbgstr_w(name_info->Name.Buffer));
512
513 /** Tests for UOI_TYPE **/
514
515 /* Get size, test size and return value/error code */
516 SetLastError(0xdeadbeef);
517 size = 0xdeadbeef;
518 ret = GetUserObjectInformationA(desk, UOI_TYPE, NULL, 0, &size);
519
520 ok(!ret, "GetUserObjectInformationA returned %x\n", ret);
521 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
522 ok(size == 16, "size is set to %d\n", size); /* Windows returns Unicode length (8*2) */
523
524 /* Get string */
525 SetLastError(0xdeadbeef);
526 size = 0xdeadbeef;
527 ret = GetUserObjectInformationA(desk, UOI_TYPE, buffer, sizeof(buffer), &size);
528
529 ok(ret, "GetUserObjectInformationA returned %x\n", ret);
530 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
531
532 ok(strcmp(buffer, "Desktop") == 0, "Buffer is set to '%s'\n", buffer);
533 ok(size == 8, "size is set to %d\n", size); /* 8 bytes in 'Desktop\0' */
534
535 /* Get size, test size and return value/error code (Unicode) */
536 size = 0xdeadbeef;
537 SetLastError(0xdeadbeef);
538 ret = GetUserObjectInformationW(desk, UOI_TYPE, NULL, 0, &size);
539
540 ok(!ret, "GetUserObjectInformationW 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); /* 16 bytes in 'Desktop\0' in Unicode */
543
544 /* Get string (Unicode) */
545 SetLastError(0xdeadbeef);
546 size = 0xdeadbeef;
547 ret = GetUserObjectInformationW(desk, UOI_TYPE, bufferW, sizeof(bufferW), &size);
548
549 ok(ret, "GetUserObjectInformationW returned %x\n", ret);
550 ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
551
552 ok(lstrcmpW(bufferW, DesktopW) == 0, "Buffer is not set to 'Desktop'\n");
553 ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */
554
555 ok(CloseDesktop(desk), "CloseDesktop failed\n");
556 }
557
558 static void test_inputdesktop(void)
559 {
560 HDESK input_desk, old_input_desk, thread_desk, old_thread_desk, new_desk;
561 DWORD ret;
562 CHAR name[1024];
563 INPUT inputs[1];
564
565 inputs[0].type = INPUT_KEYBOARD;
566 U(inputs[0]).ki.wVk = 0;
567 U(inputs[0]).ki.wScan = 0x3c0;
568 U(inputs[0]).ki.dwFlags = KEYEVENTF_UNICODE;
569
570 /* OpenInputDesktop creates new handles for each calls */
571 old_input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
572 ok(old_input_desk != NULL, "OpenInputDesktop failed!\n");
573 memset(name, 0, sizeof(name));
574 ret = GetUserObjectInformationA(old_input_desk, UOI_NAME, name, 1024, NULL);
575 ok(ret, "GetUserObjectInformation failed!\n");
576 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
577
578 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
579 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
580 memset(name, 0, sizeof(name));
581 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
582 ok(ret, "GetUserObjectInformation failed!\n");
583 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
584
585 ok(old_input_desk != input_desk, "returned the same handle!\n");
586 ret = CloseDesktop(input_desk);
587 ok(ret, "CloseDesktop failed!\n");
588
589 /* by default, GetThreadDesktop is the input desktop, SendInput should succeed. */
590 old_thread_desk = GetThreadDesktop(GetCurrentThreadId());
591 ok(old_thread_desk != NULL, "GetThreadDesktop faile!\n");
592 memset(name, 0, sizeof(name));
593 ret = GetUserObjectInformationA(old_thread_desk, UOI_NAME, name, 1024, NULL);
594 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
595
596 SetLastError(0xdeadbeef);
597 ret = SendInput(1, inputs, sizeof(INPUT));
598 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
599 ok(ret == 1, "unexpected return count %d\n", ret);
600
601 /* Set thread desktop to the new desktop, SendInput should fail. */
602 new_desk = CreateDesktopA("new_desk", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
603 ok(new_desk != NULL, "CreateDesktop failed!\n");
604 ret = SetThreadDesktop(new_desk);
605 ok(ret, "SetThreadDesktop failed!\n");
606 thread_desk = GetThreadDesktop(GetCurrentThreadId());
607 ok(thread_desk == new_desk, "thread desktop doesn't match!\n");
608 memset(name, 0, sizeof(name));
609 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
610 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
611
612 SetLastError(0xdeadbeef);
613 ret = SendInput(1, inputs, sizeof(INPUT));
614 if(broken(GetLastError() == 0xdeadbeef))
615 {
616 SetThreadDesktop(old_thread_desk);
617 CloseDesktop(old_input_desk);
618 CloseDesktop(input_desk);
619 CloseDesktop(new_desk);
620 win_skip("Skip tests on NT4\n");
621 return;
622 }
623 todo_wine
624 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError());
625 ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret);
626
627 /* Set thread desktop back to the old thread desktop, SendInput should success. */
628 ret = SetThreadDesktop(old_thread_desk);
629 ok(ret, "SetThreadDesktop failed!\n");
630 thread_desk = GetThreadDesktop(GetCurrentThreadId());
631 ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n");
632 memset(name, 0, sizeof(name));
633 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
634 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
635
636 SetLastError(0xdeadbeef);
637 ret = SendInput(1, inputs, sizeof(INPUT));
638 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
639 ok(ret == 1, "unexpected return count %d\n", ret);
640
641 /* Set thread desktop to the input desktop, SendInput should success. */
642 ret = SetThreadDesktop(old_input_desk);
643 ok(ret, "SetThreadDesktop failed!\n");
644 thread_desk = GetThreadDesktop(GetCurrentThreadId());
645 ok(thread_desk == old_input_desk, "thread desktop doesn't match!\n");
646 memset(name, 0, sizeof(name));
647 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
648 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
649
650 SetLastError(0xdeadbeef);
651 ret = SendInput(1, inputs, sizeof(INPUT));
652 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
653 ok(ret == 1, "unexpected return count %d\n", ret);
654
655 /* Switch input desktop to the new desktop, SendInput should fail. */
656 ret = SwitchDesktop(new_desk);
657 ok(ret, "SwitchDesktop failed!\n");
658 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
659 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
660 ok(input_desk != new_desk, "returned the same handle!\n");
661 memset(name, 0, sizeof(name));
662 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
663 ok(ret, "GetUserObjectInformation failed!\n");
664 todo_wine
665 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
666 ret = CloseDesktop(input_desk);
667 ok(ret, "CloseDesktop failed!\n");
668
669 SetLastError(0xdeadbeef);
670 ret = SendInput(1, inputs, sizeof(INPUT));
671 todo_wine
672 ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError());
673 ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret);
674
675 /* Set thread desktop to the new desktop, SendInput should success. */
676 ret = SetThreadDesktop(new_desk);
677 ok(ret, "SetThreadDesktop failed!\n");
678 thread_desk = GetThreadDesktop(GetCurrentThreadId());
679 ok(thread_desk == new_desk, "thread desktop doesn't match!\n");
680 memset(name, 0, sizeof(name));
681 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
682 ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
683
684 SetLastError(0xdeadbeef);
685 ret = SendInput(1, inputs, sizeof(INPUT));
686 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
687 ok(ret == 1, "unexpected return count %d\n", ret);
688
689 /* Switch input desktop to the old input desktop, set thread desktop to the old
690 * thread desktop, clean side effects. SendInput should success. */
691 ret = SwitchDesktop(old_input_desk);
692 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
693 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
694 ok(input_desk != old_input_desk, "returned the same handle!\n");
695 memset(name, 0, sizeof(name));
696 ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
697 ok(ret, "GetUserObjectInformation failed!\n");
698 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
699
700 ret = SetThreadDesktop(old_thread_desk);
701 ok(ret, "SetThreadDesktop failed!\n");
702 thread_desk = GetThreadDesktop(GetCurrentThreadId());
703 ok(thread_desk == old_thread_desk, "thread desktop doesn't match!\n");
704 memset(name, 0, sizeof(name));
705 ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
706 ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
707
708 SetLastError(0xdeadbeef);
709 ret = SendInput(1, inputs, sizeof(INPUT));
710 ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError());
711 ok(ret == 1, "unexpected return count %d\n", ret);
712
713 /* free resources */
714 ret = CloseDesktop(input_desk);
715 ok(ret, "CloseDesktop failed!\n");
716 ret = CloseDesktop(old_input_desk);
717 ok(ret, "CloseDesktop failed!\n");
718 ret = CloseDesktop(new_desk);
719 ok(ret, "CloseDesktop failed!\n");
720 }
721
722 static void test_inputdesktop2(void)
723 {
724 HWINSTA w1, w2;
725 HDESK thread_desk, new_desk, input_desk, hdesk;
726 DWORD ret;
727
728 thread_desk = GetThreadDesktop(GetCurrentThreadId());
729 ok(thread_desk != NULL, "GetThreadDesktop failed!\n");
730 w1 = GetProcessWindowStation();
731 ok(w1 != NULL, "GetProcessWindowStation failed!\n");
732 SetLastError(0xdeadbeef);
733 w2 = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL);
734 ret = GetLastError();
735 ok(w2 != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret);
736 if (!w2)
737 {
738 win_skip("Not enough privileges for CreateWindowStation\n");
739 return;
740 }
741
742 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
743 ok(!ret, "EnumDesktopsA failed!\n");
744 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
745 ok(input_desk != NULL, "OpenInputDesktop failed!\n");
746 ret = CloseDesktop(input_desk);
747 ok(ret, "CloseDesktop failed!\n");
748
749 ret = SetProcessWindowStation(w2);
750 ok(ret, "SetProcessWindowStation failed!\n");
751 hdesk = GetThreadDesktop(GetCurrentThreadId());
752 ok(hdesk != NULL, "GetThreadDesktop failed!\n");
753 ok(hdesk == thread_desk, "thread desktop should not change after winstation changed!\n");
754 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
755
756 new_desk = CreateDesktopA("desk_test", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
757 ok(new_desk != NULL, "CreateDesktop failed!\n");
758 ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
759 ok(!ret, "EnumDesktopsA failed!\n");
760 SetLastError(0xdeadbeef);
761 input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
762 ok(input_desk == NULL, "OpenInputDesktop should fail on non default winstation!\n");
763 ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
764
765 hdesk = OpenDesktopA("desk_test", 0, TRUE, DESKTOP_ALL_ACCESS);
766 ok(hdesk != NULL, "OpenDesktop failed!\n");
767 SetLastError(0xdeadbeef);
768 ret = SwitchDesktop(hdesk);
769 todo_wine
770 ok(!ret, "Switch to desktop belong to non default winstation should fail!\n");
771 todo_wine
772 ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
773 ret = SetThreadDesktop(hdesk);
774 ok(ret, "SetThreadDesktop failed!\n");
775
776 /* clean side effect */
777 ret = SetThreadDesktop(thread_desk);
778 todo_wine
779 ok(ret, "SetThreadDesktop should success even desktop is not belong to process winstation!\n");
780 ret = SetProcessWindowStation(w1);
781 ok(ret, "SetProcessWindowStation failed!\n");
782 ret = SetThreadDesktop(thread_desk);
783 ok(ret, "SetThreadDesktop failed!\n");
784 ret = CloseWindowStation(w2);
785 ok(ret, "CloseWindowStation failed!\n");
786 ret = CloseDesktop(new_desk);
787 ok(ret, "CloseDesktop failed!\n");
788 ret = CloseDesktop(hdesk);
789 ok(ret, "CloseDesktop failed!\n");
790 }
791
792 static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
793 {
794 if (msg == WM_DESTROY)
795 {
796 trace("destroying hwnd %p\n", hWnd);
797 PostQuitMessage(0);
798 return 0;
799 }
800 return DefWindowProcA( hWnd, msg, wParam, lParam );
801 }
802
803 typedef struct tag_wnd_param
804 {
805 const char *wnd_name;
806 HWND hwnd;
807 HDESK hdesk;
808 HANDLE hevent;
809 } wnd_param;
810
811 static DWORD WINAPI create_window(LPVOID param)
812 {
813 wnd_param *param1 = param;
814 DWORD ret;
815 MSG msg;
816
817 ret = SetThreadDesktop(param1->hdesk);
818 ok(ret, "SetThreadDesktop failed!\n");
819 param1->hwnd = CreateWindowA("test_class", param1->wnd_name, WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
820 ok(param1->hwnd != 0, "CreateWindowA failed!\n");
821 ret = SetEvent(param1->hevent);
822 ok(ret, "SetEvent failed!\n");
823
824 while (GetMessageA(&msg, 0, 0, 0))
825 {
826 TranslateMessage(&msg);
827 DispatchMessageA(&msg);
828 }
829
830 return 0;
831 }
832
833 static DWORD set_foreground(HWND hwnd)
834 {
835 HWND hwnd_fore;
836 DWORD set_id, fore_id, ret;
837 char win_text[1024];
838
839 hwnd_fore = GetForegroundWindow();
840 GetWindowTextA(hwnd_fore, win_text, 1024);
841 set_id = GetWindowThreadProcessId(hwnd, NULL);
842 fore_id = GetWindowThreadProcessId(hwnd_fore, NULL);
843 trace("\"%s\" %p %08x hwnd %p %08x\n", win_text, hwnd_fore, fore_id, hwnd, set_id);
844 ret = AttachThreadInput(set_id, fore_id, TRUE);
845 trace("AttachThreadInput returned %08x\n", ret);
846 ret = ShowWindow(hwnd, SW_SHOWNORMAL);
847 trace("ShowWindow returned %08x\n", ret);
848 ret = SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
849 trace("set topmost returned %08x\n", ret);
850 ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
851 trace("set notopmost returned %08x\n", ret);
852 ret = SetForegroundWindow(hwnd);
853 trace("SetForegroundWindow returned %08x\n", ret);
854 Sleep(250);
855 AttachThreadInput(set_id, fore_id, FALSE);
856 return ret;
857 }
858
859 static void test_foregroundwindow(void)
860 {
861 HWND hwnd, hwnd_test, partners[2], hwnds[2];
862 HDESK hdesks[2];
863 int thread_desk_id, input_desk_id, hwnd_id;
864 WNDCLASSA wclass;
865 wnd_param param;
866 DWORD ret, timeout, timeout_old;
867 char win_text[1024];
868
869 #define DESKTOPS 2
870
871 memset( &wclass, 0, sizeof(wclass) );
872 wclass.lpszClassName = "test_class";
873 wclass.lpfnWndProc = WndProc;
874 RegisterClassA(&wclass);
875 param.wnd_name = "win_name";
876
877 hdesks[0] = GetThreadDesktop(GetCurrentThreadId());
878 ok(hdesks[0] != NULL, "OpenDesktop failed!\n");
879 SetLastError(0xdeadbeef);
880 hdesks[1] = CreateDesktopA("desk2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
881 ret = GetLastError();
882 ok(hdesks[1] != NULL || ret == ERROR_ACCESS_DENIED, "CreateDesktop failed (%u)\n", ret);
883 if(!hdesks[1])
884 {
885 win_skip("Not enough privileges for CreateDesktop\n");
886 return;
887 }
888
889 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout_old, 0);
890 if(!ret)
891 {
892 win_skip("Skip tests on NT4\n");
893 CloseDesktop(hdesks[1]);
894 return;
895 }
896 trace("old timeout %d\n", timeout_old);
897 timeout = 0;
898 ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
899 ok(ret, "set foreground lock timeout failed!\n");
900 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0);
901 ok(ret, "get foreground lock timeout failed!\n");
902 ok(timeout == 0, "unexpected timeout %d\n", timeout);
903
904 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
905 {
906 param.hdesk = hdesks[thread_desk_id];
907 param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL);
908 CreateThread(NULL, 0, create_window, &param, 0, NULL);
909 ret = WaitForSingleObject(param.hevent, INFINITE);
910 ok(ret == WAIT_OBJECT_0, "wait failed!\n");
911 hwnds[thread_desk_id] = param.hwnd;
912 }
913
914 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
915 {
916 param.hdesk = hdesks[thread_desk_id];
917 param.hevent = CreateEventA(NULL, TRUE, FALSE, NULL);
918 CreateThread(NULL, 0, create_window, &param, 0, NULL);
919 ret = WaitForSingleObject(param.hevent, INFINITE);
920 ok(ret == WAIT_OBJECT_0, "wait failed!\n");
921 partners[thread_desk_id] = param.hwnd;
922 }
923
924 trace("hwnd0 %p hwnd1 %p partner0 %p partner1 %p\n", hwnds[0], hwnds[1], partners[0], partners[1]);
925
926 for (hwnd_id = 0; hwnd_id < DESKTOPS; hwnd_id++)
927 for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++)
928 for (input_desk_id = 0; input_desk_id < DESKTOPS; input_desk_id++)
929 {
930 trace("testing thread_desk %d input_desk %d hwnd %d\n",
931 thread_desk_id, input_desk_id, hwnd_id);
932 hwnd_test = hwnds[hwnd_id];
933 ret = SetThreadDesktop(hdesks[thread_desk_id]);
934 ok(ret, "set thread desktop failed!\n");
935 ret = SwitchDesktop(hdesks[input_desk_id]);
936 ok(ret, "switch desktop failed!\n");
937 set_foreground(partners[0]);
938 set_foreground(partners[1]);
939 hwnd = GetForegroundWindow();
940 ok(hwnd != hwnd_test, "unexpected foreground window %p\n", hwnd);
941 ret = set_foreground(hwnd_test);
942 hwnd = GetForegroundWindow();
943 GetWindowTextA(hwnd, win_text, 1024);
944 trace("hwnd %p name %s\n", hwnd, win_text);
945 if (input_desk_id == hwnd_id)
946 {
947 if (input_desk_id == thread_desk_id)
948 {
949 ok(ret, "SetForegroundWindow failed!\n");
950 todo_wine_if (!hwnd)
951 ok(hwnd == hwnd_test , "unexpected foreground window %p\n", hwnd);
952 }
953 else
954 {
955 todo_wine ok(ret, "SetForegroundWindow failed!\n");
956 todo_wine ok(hwnd == 0, "unexpected foreground window %p\n", hwnd);
957 }
958 }
959 else
960 {
961 if (input_desk_id == thread_desk_id)
962 {
963 ok(!ret, "SetForegroundWindow should fail!\n");
964 todo_wine_if (!hwnd)
965 ok(hwnd == partners[input_desk_id] , "unexpected foreground window %p\n", hwnd);
966 }
967 else
968 {
969 todo_wine ok(!ret, "SetForegroundWindow should fail!\n");
970 todo_wine_if (hwnd)
971 ok(hwnd == 0, "unexpected foreground window %p\n", hwnd);
972 }
973 }
974 }
975
976 /* Clean up */
977
978 for (thread_desk_id = DESKTOPS - 1; thread_desk_id >= 0; thread_desk_id--)
979 {
980 ret = SetThreadDesktop(hdesks[thread_desk_id]);
981 ok(ret, "set thread desktop failed!\n");
982 SendMessageA(hwnds[thread_desk_id], WM_DESTROY, 0, 0);
983 SendMessageA(partners[thread_desk_id], WM_DESTROY, 0, 0);
984 }
985
986 ret = SwitchDesktop(hdesks[0]);
987 ok(ret, "switch desktop failed!\n");
988 CloseDesktop(hdesks[1]);
989
990 ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UlongToPtr(timeout_old), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
991 ok(ret, "set foreground lock timeout failed!\n");
992 ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0);
993 ok(ret, "get foreground lock timeout failed!\n");
994 ok(timeout == timeout_old, "unexpected timeout %d\n", timeout);
995 }
996
997 START_TEST(winstation)
998 {
999 HMODULE hntdll = GetModuleHandleA("ntdll.dll");
1000 pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject");
1001
1002 /* Check whether this platform supports WindowStation calls */
1003
1004 SetLastError( 0xdeadbeef );
1005 GetProcessWindowStation();
1006 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1007 {
1008 win_skip("WindowStation calls not supported on this platform\n");
1009 return;
1010 }
1011
1012 test_inputdesktop();
1013 test_inputdesktop2();
1014 test_enumstations();
1015 test_enumdesktops();
1016 test_handles();
1017 test_getuserobjectinformation();
1018 test_foregroundwindow();
1019 }