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