user32/tests: Add GetUserObjectInformation tests.
[wine] / dlls / user32 / tests / 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, 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 = CreateDesktop( "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 = CreateWindowStation("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 = CreateWindowStation("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 = OpenWindowStation("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 = OpenWindowStation("dummy name", TRUE, WINSTA_ALL_ACCESS );
163     ok( !w2, "open dummy win station succeeded\n" );
164
165     CreateMutexA( NULL, 0, "foobar" );
166     w2 = CreateWindowStation("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 = OpenWindowStation("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 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
179         ok( !w3, "open foobar station succeeded\n" );
180
181         w2 = CreateWindowStation("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
182         ok( w2 != 0, "create foobar station failed\n" );
183         w3 = CreateWindowStation("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 = OpenDesktop( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
237     ok( !d2, "open dummy desktop succeeded\n" );
238
239     d2 = CreateDesktop( "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 = CreateDesktop( "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 = OpenDesktop( "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 = OpenDesktop( "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
275 /* Enumeration tests */
276
277 static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp)
278 {
279     trace("window_station_callbackA called with argument %s\n", winsta);
280     return lp;
281 }
282
283 static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp)
284 {
285     HWINSTA hwinsta;
286
287     trace("open_window_station_callbackA called with argument %s\n", winsta);
288     hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE);
289     ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta);
290     if (hwinsta)
291         CloseWindowStation(hwinsta);
292     return lp;
293 }
294
295 static void test_enumstations(void)
296 {
297     BOOL ret;
298
299     if (0) /* Crashes instead */
300     {
301         SetLastError(0xbabefeed);
302         ret = EnumWindowStationsA(NULL, 0);
303         ok(!ret, "EnumWindowStationsA returned successfully!\n");
304         ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
305     }
306
307     SetLastError(0xdeadbeef);
308     ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345);
309     ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret);
310     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
311
312     SetLastError(0xdeadbeef);
313     ret = EnumWindowStationsA(window_station_callbackA, 0);
314     ok(!ret, "EnumWindowStationsA returned %x\n", ret);
315     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
316 }
317
318 static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp)
319 {
320     trace("desktop_callbackA called with argument %s\n", desktop);
321     return lp;
322 }
323
324 static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp)
325 {
326     HDESK hdesk;
327     static int once;
328
329     trace("open_desktop_callbackA called with argument %s\n", desktop);
330     /* Only try to open one desktop */
331     if (once++)
332         return lp;
333
334     hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE);
335     ok(hdesk != NULL, "Could not open desktop %s!\n", desktop);
336     if (hdesk)
337         CloseDesktop(hdesk);
338     return lp;
339 }
340
341 static void test_enumdesktops(void)
342 {
343     BOOL ret;
344
345     if (0)  /* Crashes instead */
346     {
347         SetLastError(0xbabefeed);
348         ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0);
349         ok(!ret, "EnumDesktopsA returned successfully!\n");
350         ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
351     }
352
353     SetLastError(0xdeadbeef);
354     ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345);
355     ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
356     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
357
358     SetLastError(0xdeadbeef);
359     ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345);
360     ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
361     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
362
363     SetLastError(0xdeadbeef);
364     ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345);
365     ok(!ret, "EnumDesktopsA returned %x\n", ret);
366     ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError());
367
368     SetLastError(0xdeadbeef);
369     ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
370     ok(!ret, "EnumDesktopsA returned %x\n", ret);
371     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
372 }
373
374 /* Miscellaneous tests */
375
376 static void test_getuserobjectinformation(void)
377 {
378     HDESK desk;
379     WCHAR bufferW[20];
380     char buffer[20];
381     WCHAR foobarTestW[] = {'f','o','o','b','a','r','T','e','s','t',0};
382     WCHAR DesktopW[] = {'D','e','s','k','t','o','p',0};
383     DWORD size;
384     BOOL ret;
385
386     desk = CreateDesktop("foobarTest", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
387     ok(desk != 0, "open foobarTest desktop failed\n");
388
389     strcpy(buffer, "blahblah");
390
391     /** Tests for UOI_NAME **/
392
393     /* Get size, test size and return value/error code */
394     SetLastError(0xdeadbeef);
395     size = 0xdeadbeef;
396     ret = GetUserObjectInformationA(desk, UOI_NAME, NULL, 0, &size);
397
398     ok(!ret, "GetUserObjectInformationA returned %x", ret);
399     todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
400     todo_wine ok(size == 22, "size is set to %d\n", size); /* Windows returns Unicode length (11*2) */
401
402     /* Get string */
403     SetLastError(0xdeadbeef);
404     size = 0xdeadbeef;
405     ret = GetUserObjectInformationA(desk, UOI_NAME, buffer, sizeof(buffer), &size);
406
407     ok(ret, "GetUserObjectInformationA returned %x", ret);
408     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
409
410     ok(strcmp(buffer, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer);
411     ok(size == 11, "size is set to %d\n", size); /* 11 bytes in 'foobarTest\0' */
412
413     /* Get size, test size and return value/error code (Unicode) */
414     SetLastError(0xdeadbeef);
415     size = 0xdeadbeef;
416     ret = GetUserObjectInformationW(desk, UOI_NAME, NULL, 0, &size);
417
418     ok(!ret, "GetUserObjectInformationW returned %x", ret);
419     todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
420     ok(size == 22, "size is set to %d\n", size);  /* 22 bytes in 'foobarTest\0' in Unicode */
421
422     /* Get string (Unicode) */
423     SetLastError(0xdeadbeef);
424     size = 0xdeadbeef;
425     ret = GetUserObjectInformationW(desk, UOI_NAME, bufferW, sizeof(bufferW), &size);
426
427     ok(ret, "GetUserObjectInformationW returned %x", ret);
428     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
429
430     ok(lstrcmpW(bufferW, foobarTestW) == 0, "Buffer is not set to 'foobarTest'\n");
431     ok(size == 22, "size is set to %d\n", size);  /* 22 bytes in 'foobarTest\0' in Unicode */
432
433     /** Tests for UOI_TYPE **/
434
435     /* Get size, test size and return value/error code */
436     SetLastError(0xdeadbeef);
437     size = 0xdeadbeef;
438     ret = GetUserObjectInformationA(desk, UOI_TYPE, NULL, 0, &size);
439
440     ok(!ret, "GetUserObjectInformationA returned %x", ret);
441     todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
442     todo_wine ok(size == 16, "size is set to %d\n", size); /* Windows returns Unicode length (8*2) */
443
444     /* Get string */
445     SetLastError(0xdeadbeef);
446     size = 0xdeadbeef;
447     ret = GetUserObjectInformationA(desk, UOI_TYPE, buffer, sizeof(buffer), &size);
448
449     ok(ret, "GetUserObjectInformationA returned %x", ret);
450     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
451
452     ok(strcmp(buffer, "Desktop") == 0, "Buffer is set to '%s'\n", buffer);
453     ok(size == 8, "size is set to %d\n", size); /* 8 bytes in 'Desktop\0' */
454
455     /* Get size, test size and return value/error code (Unicode) */
456     size = 0xdeadbeef;
457     SetLastError(0xdeadbeef);
458     ret = GetUserObjectInformationW(desk, UOI_TYPE, NULL, 0, &size);
459
460     ok(!ret, "GetUserObjectInformationW returned %x", ret);
461     todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError());
462     ok(size == 16, "size is set to %d\n", size);  /* 16 bytes in 'Desktop\0' in Unicode */
463
464     /* Get string (Unicode) */
465     SetLastError(0xdeadbeef);
466     size = 0xdeadbeef;
467     ret = GetUserObjectInformationW(desk, UOI_TYPE, bufferW, sizeof(bufferW), &size);
468
469     ok(ret, "GetUserObjectInformationW returned %x", ret);
470     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
471
472     ok(lstrcmpW(bufferW, DesktopW) == 0, "Buffer is not set to 'Desktop'\n");
473     ok(size == 16, "size is set to %d\n", size);  /* 16 bytes in 'Desktop\0' in Unicode */
474
475     ok(CloseDesktop(desk), "CloseDesktop failed\n");
476 }
477
478 START_TEST(winstation)
479 {
480     /* Check whether this platform supports WindowStation calls */
481
482     SetLastError( 0xdeadbeef );
483     GetProcessWindowStation();
484     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
485     {
486         skip("WindowStation calls not supported on this platform\n");
487         return;
488     }
489
490     test_enumstations();
491     test_enumdesktops();
492     test_handles();
493     test_getuserobjectinformation();
494 }