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