user32/tests: Skip tests instead of crashing if global hook cannot be set.
[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
26 #define DESKTOP_ALL_ACCESS 0x01ff
27
28 static void print_object( HANDLE obj )
29 {
30     char buffer[100];
31     DWORD size;
32
33     strcpy( buffer, "foobar" );
34     if (!GetUserObjectInformationA( obj, UOI_NAME, buffer, sizeof(buffer), &size ))
35         trace( "could not get info for %p\n", obj );
36     else
37         trace( "obj %p name '%s'\n", obj, buffer );
38     strcpy( buffer, "foobar" );
39     if (!GetUserObjectInformationA( obj, UOI_TYPE, buffer, sizeof(buffer), &size ))
40         trace( "could not get type for %p\n", obj );
41     else
42         trace( "obj %p type '%s'\n", obj, buffer );
43 }
44
45 static void register_class(void)
46 {
47     WNDCLASSA cls;
48
49     cls.style = CS_DBLCLKS;
50     cls.lpfnWndProc = DefWindowProcA;
51     cls.cbClsExtra = 0;
52     cls.cbWndExtra = 0;
53     cls.hInstance = GetModuleHandleA(0);
54     cls.hIcon = 0;
55     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
56     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
57     cls.lpszMenuName = NULL;
58     cls.lpszClassName = "WinStationClass";
59     RegisterClassA(&cls);
60 }
61
62 static HDESK initial_desktop;
63
64 static DWORD CALLBACK thread( LPVOID arg )
65 {
66     HDESK d1, d2;
67     HWND hwnd = CreateWindowExA(0,"WinStationClass","test",WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
68     ok( hwnd != 0, "CreateWindow failed\n" );
69     d1 = GetThreadDesktop(GetCurrentThreadId());
70     trace( "thread %p desktop: %p\n", arg, d1 );
71     ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg );
72
73     SetLastError( 0xdeadbeef );
74     ok( !CloseHandle( d1 ), "CloseHandle succeeded\n" );
75     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
76     SetLastError( 0xdeadbeef );
77     ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" );
78     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
79     print_object( d1 );
80     d2 = CreateDesktop( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
81     trace( "created desktop %p\n", d2 );
82     ok( d2 != 0, "CreateDesktop failed\n" );
83
84     SetLastError( 0xdeadbeef );
85     ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
86     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
87
88     DestroyWindow( hwnd );
89     ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" );
90     d1 = GetThreadDesktop(GetCurrentThreadId());
91     ok( d1 == d2, "GetThreadDesktop did not return set desktop %p/%p\n", d1, d2 );
92     print_object( d2 );
93     if (arg < (LPVOID)5)
94     {
95         HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL );
96         Sleep(1000);
97         WaitForSingleObject( hthread, INFINITE );
98         CloseHandle( hthread );
99     }
100     return 0;
101 }
102
103 static void test_handles(void)
104 {
105     HWINSTA w1, w2, w3;
106     HDESK d1, d2, d3;
107     HANDLE hthread;
108     DWORD id, flags;
109     ATOM atom;
110     char buffer[20];
111
112     /* win stations */
113
114     w1 = GetProcessWindowStation();
115     ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" );
116     ok( !CloseWindowStation(w1), "closing process win station succeeded\n" );
117     SetLastError( 0xdeadbeef );
118     ok( !CloseHandle(w1), "closing process win station handle succeeded\n" );
119     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
120     print_object( w1 );
121
122     flags = 0;
123     ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
124     ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", w1 );
125
126     ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
127                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
128     ok( CloseWindowStation(w2), "closing dup win station failed\n" );
129
130     ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
131                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
132     ok( CloseHandle(w2), "closing dup win station handle failed\n" );
133
134     w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
135     ok( w2 != 0, "CreateWindowStation failed\n" );
136     ok( w2 != w1, "CreateWindowStation returned default handle\n" );
137     SetLastError( 0xdeadbeef );
138     ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" );
139     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
140     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
141
142     w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
143     ok( CloseHandle( w2 ), "CloseHandle failed\n" );
144
145     w2 = OpenWindowStation("winsta0", TRUE, WINSTA_ALL_ACCESS );
146     ok( w2 != 0, "OpenWindowStation failed\n" );
147     ok( w2 != w1, "OpenWindowStation returned default handle\n" );
148     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
149
150     w2 = OpenWindowStation("dummy name", TRUE, WINSTA_ALL_ACCESS );
151     ok( !w2, "open dummy win station succeeded\n" );
152
153     CreateMutexA( NULL, 0, "foobar" );
154     w2 = CreateWindowStation("foobar", 0, WINSTA_ALL_ACCESS, NULL );
155     ok( w2 != 0, "create foobar station failed\n" );
156
157     w3 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
158     ok( w3 != 0, "open foobar station failed\n" );
159     ok( w3 != w2, "open foobar station returned same handle\n" );
160     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
161     ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" );
162
163     w3 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
164     ok( !w3, "open foobar station succeeded\n" );
165
166     w2 = CreateWindowStation("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
167     ok( w2 != 0, "create foobar station failed\n" );
168     w3 = CreateWindowStation("foobar2", 0, WINSTA_ALL_ACCESS, NULL );
169     ok( w3 != 0, "create foobar station failed\n" );
170     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
171     ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" );
172
173     SetProcessWindowStation( w2 );
174     register_class();
175     atom = GlobalAddAtomA("foo");
176     ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
177     ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
178
179     ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" );
180     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
181
182     SetProcessWindowStation( w3 );
183     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
184     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
185     ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
186     ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
187
188     /* desktops */
189     d1 = GetThreadDesktop(GetCurrentThreadId());
190     initial_desktop = d1;
191     ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
192         "GetThreadDesktop returned different handles\n" );
193
194     flags = 0;
195     ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" );
196     ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 );
197
198     SetLastError( 0xdeadbeef );
199     ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" );
200     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
201
202     SetLastError( 0xdeadbeef );
203     ok( !CloseHandle(d1), "closing thread desktop handle failed\n" );
204     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
205
206     ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
207                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
208     ok( CloseDesktop(d2), "closing dup desktop failed\n" );
209
210     ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
211                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
212     ok( CloseHandle(d2), "closing dup desktop handle failed\n" );
213
214     d2 = OpenDesktop( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
215     ok( !d2, "open dummy desktop succeeded\n" );
216
217     d2 = CreateDesktop( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
218     ok( d2 != 0, "create foobar desktop failed\n" );
219     SetLastError( 0xdeadbeef );
220     ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" );
221     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
222
223     d3 = OpenDesktop( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
224     ok( d3 != 0, "open foobar desktop failed\n" );
225     ok( d3 != d2, "open foobar desktop returned same handle\n" );
226     ok( CloseDesktop( d2 ), "CloseDesktop failed\n" );
227     ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
228
229     d3 = OpenDesktop( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
230     ok( !d3, "open foobar desktop succeeded\n" );
231
232     ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" );
233     d2 = GetThreadDesktop(GetCurrentThreadId());
234     ok( d1 == d2, "got different handles after close\n" );
235
236     trace( "thread 1 desktop: %p\n", d1 );
237     print_object( d1 );
238     hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
239     Sleep(1000);
240     trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
241     WaitForSingleObject( hthread, INFINITE );
242     CloseHandle( hthread );
243 }
244
245 START_TEST(winstation)
246 {
247     /* Check whether this platform supports WindowStation calls */
248
249     SetLastError( 0xdeadbeef );
250     GetProcessWindowStation();
251     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
252     {
253         skip("WindowStation calls not supported on this platform\n");
254         return;
255     }
256
257     test_handles();
258 }