user32/tests: Abstract the printing of minmax info and do it all on one line.
[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, (LPSTR)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, "bad last error %d\n", GetLastError() );
80     print_object( d1 );
81     d2 = CreateDesktop( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
82     trace( "created desktop %p\n", d2 );
83     ok( d2 != 0, "CreateDesktop failed\n" );
84
85     SetLastError( 0xdeadbeef );
86     ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
87     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
88
89     DestroyWindow( hwnd );
90     ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" );
91     d1 = GetThreadDesktop(GetCurrentThreadId());
92     ok( d1 == d2, "GetThreadDesktop did not return set desktop %p/%p\n", d1, d2 );
93     print_object( d2 );
94     if (arg < (LPVOID)5)
95     {
96         HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL );
97         Sleep(1000);
98         WaitForSingleObject( hthread, INFINITE );
99         CloseHandle( hthread );
100     }
101     return 0;
102 }
103
104 static void test_handles(void)
105 {
106     HWINSTA w1, w2, w3;
107     HDESK d1, d2, d3;
108     HANDLE hthread;
109     DWORD id, flags;
110     ATOM atom;
111     char buffer[20];
112
113     /* win stations */
114
115     w1 = GetProcessWindowStation();
116     ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" );
117     ok( !CloseWindowStation(w1), "closing process win station succeeded\n" );
118     SetLastError( 0xdeadbeef );
119     ok( !CloseHandle(w1), "closing process win station handle succeeded\n" );
120     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
121     print_object( w1 );
122
123     flags = 0;
124     ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
125     ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", w1 );
126
127     ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
128                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
129     ok( CloseWindowStation(w2), "closing dup win station failed\n" );
130
131     ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
132                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
133     ok( CloseHandle(w2), "closing dup win station handle failed\n" );
134
135     w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
136     ok( w2 != 0, "CreateWindowStation failed\n" );
137     ok( w2 != w1, "CreateWindowStation returned default handle\n" );
138     SetLastError( 0xdeadbeef );
139     ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" );
140     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
141     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
142
143     w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
144     ok( CloseHandle( w2 ), "CloseHandle failed\n" );
145
146     w2 = OpenWindowStation("winsta0", TRUE, WINSTA_ALL_ACCESS );
147     ok( w2 != 0, "OpenWindowStation failed\n" );
148     ok( w2 != w1, "OpenWindowStation returned default handle\n" );
149     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
150
151     w2 = OpenWindowStation("dummy name", TRUE, WINSTA_ALL_ACCESS );
152     ok( !w2, "open dummy win station succeeded\n" );
153
154     CreateMutexA( NULL, 0, "foobar" );
155     w2 = CreateWindowStation("foobar", 0, WINSTA_ALL_ACCESS, NULL );
156     ok( w2 != 0, "create foobar station failed\n" );
157
158     w3 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
159     ok( w3 != 0, "open foobar station failed\n" );
160     ok( w3 != w2, "open foobar station returned same handle\n" );
161     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
162     ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" );
163
164     w3 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
165     ok( !w3, "open foobar station succeeded\n" );
166
167     w2 = CreateWindowStation("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
168     ok( w2 != 0, "create foobar station failed\n" );
169     w3 = CreateWindowStation("foobar2", 0, WINSTA_ALL_ACCESS, NULL );
170     ok( w3 != 0, "create foobar station failed\n" );
171     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
172     ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" );
173
174     SetProcessWindowStation( w2 );
175     register_class();
176     atom = GlobalAddAtomA("foo");
177     ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
178     ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
179
180     ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" );
181     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
182
183     SetProcessWindowStation( w3 );
184     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
185     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
186     ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
187     ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
188
189     /* desktops */
190     d1 = GetThreadDesktop(GetCurrentThreadId());
191     initial_desktop = d1;
192     ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
193         "GetThreadDesktop returned different handles\n" );
194
195     flags = 0;
196     ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" );
197     ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 );
198
199     SetLastError( 0xdeadbeef );
200     ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" );
201     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
202
203     SetLastError( 0xdeadbeef );
204     ok( !CloseHandle(d1), "closing thread desktop handle failed\n" );
205     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
206
207     ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
208                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
209     ok( CloseDesktop(d2), "closing dup desktop failed\n" );
210
211     ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
212                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
213     ok( CloseHandle(d2), "closing dup desktop handle failed\n" );
214
215     d2 = OpenDesktop( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
216     ok( !d2, "open dummy desktop succeeded\n" );
217
218     d2 = CreateDesktop( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
219     ok( d2 != 0, "create foobar desktop failed\n" );
220     SetLastError( 0xdeadbeef );
221     ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" );
222     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
223
224     SetLastError( 0xdeadbeef );
225     d3 = CreateDesktop( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
226     ok( d3 != 0, "create foobar desktop again failed\n" );
227     ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() );
228     ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
229
230     d3 = OpenDesktop( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
231     ok( d3 != 0, "open foobar desktop failed\n" );
232     ok( d3 != d2, "open foobar desktop returned same handle\n" );
233     ok( CloseDesktop( d2 ), "CloseDesktop failed\n" );
234     ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
235
236     d3 = OpenDesktop( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
237     ok( !d3, "open foobar desktop succeeded\n" );
238
239     ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" );
240     d2 = GetThreadDesktop(GetCurrentThreadId());
241     ok( d1 == d2, "got different handles after close\n" );
242
243     trace( "thread 1 desktop: %p\n", d1 );
244     print_object( d1 );
245     hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
246     Sleep(1000);
247     trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
248     WaitForSingleObject( hthread, INFINITE );
249     CloseHandle( hthread );
250 }
251
252 /* Enumeration tests */
253
254 static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp)
255 {
256     trace("window_station_callbackA called with argument %s\n", winsta);
257     return lp;
258 }
259
260 static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp)
261 {
262     HWINSTA hwinsta;
263
264     trace("open_window_station_callbackA called with argument %s\n", winsta);
265     hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE);
266     ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta);
267     if (hwinsta)
268         CloseWindowStation(hwinsta);
269     return lp;
270 }
271
272 static void test_enumstations(void)
273 {
274     BOOL ret;
275
276     if (0) /* Crashes instead */
277     {
278         SetLastError(0xbabefeed);
279         ret = EnumWindowStationsA(NULL, 0);
280         ok(!ret, "EnumWindowStationsA returned successfully!\n");
281         ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
282     }
283
284     SetLastError(0xdeadbeef);
285     ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345);
286     ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret);
287     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
288
289     SetLastError(0xdeadbeef);
290     ret = EnumWindowStationsA(window_station_callbackA, 0);
291     ok(!ret, "EnumWindowStationsA returned %x\n", ret);
292     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
293 }
294
295 static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp)
296 {
297     trace("desktop_callbackA called with argument %s\n", desktop);
298     return lp;
299 }
300
301 static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp)
302 {
303     HDESK hdesk;
304     static int once;
305
306     trace("open_desktop_callbackA called with argument %s\n", desktop);
307     /* Only try to open one desktop */
308     if (once++)
309         return lp;
310
311     hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE);
312     ok(hdesk != NULL, "Could not open desktop %s!\n", desktop);
313     if (hdesk)
314         CloseDesktop(hdesk);
315     return lp;
316 }
317
318 static void test_enumdesktops(void)
319 {
320     BOOL ret;
321
322     if (0)  /* Crashes instead */
323     {
324         SetLastError(0xbabefeed);
325         ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0);
326         ok(!ret, "EnumDesktopsA returned successfully!\n");
327         ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
328     }
329
330     SetLastError(0xdeadbeef);
331     ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345);
332     ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
333     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
334
335     SetLastError(0xdeadbeef);
336     ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345);
337     ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
338     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
339
340     SetLastError(0xdeadbeef);
341     ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345);
342     ok(!ret, "EnumDesktopsA returned %x\n", ret);
343     ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError());
344
345     SetLastError(0xdeadbeef);
346     ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
347     ok(!ret, "EnumDesktopsA returned %x\n", ret);
348     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
349 }
350
351 START_TEST(winstation)
352 {
353     /* Check whether this platform supports WindowStation calls */
354
355     SetLastError( 0xdeadbeef );
356     GetProcessWindowStation();
357     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
358     {
359         skip("WindowStation calls not supported on this platform\n");
360         return;
361     }
362
363     test_enumstations();
364     test_enumdesktops();
365     test_handles();
366 }