e1ad9a698b232de993b6a4f227c6211bb802b277
[reactos.git] / rostests / apitests / user32 / desktop.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for desktop objects
5 * PROGRAMMERS: Giannis Adamopoulos
6 * Thomas Faber
7 */
8
9 #define WIN32_NO_STATUS
10 #include <apitest.h>
11
12 #include <stdio.h>
13 #include <wingdi.h>
14 #include <winuser.h>
15 #include "helper.h"
16 #include <ndk/umtypes.h>
17 #include <ndk/obfuncs.h>
18
19 #define DESKTOP_ALL_ACCESS 0x01ff
20
21 struct test_info {
22 WCHAR* ExpectedWinsta;
23 WCHAR* ExpectedDesktp;
24 };
25
26 struct test_info TestResults[] = {{L"WinSta0",L"Default"},
27 {L"WinSta0",L"Default"},
28 {L"WinSta0",L"Default"},
29 {NULL, NULL},
30 {NULL, NULL},
31 {NULL, NULL},
32 {NULL, NULL},
33 {L"WinSta0",L"Default"},
34 {L"TestWinsta", L"TestDesktop"},
35 {NULL, NULL}};
36
37 void do_InitialDesktop_child(int i)
38 {
39 HDESK hdesktop;
40 HWINSTA hwinsta;
41 WCHAR buffer[100];
42 DWORD size;
43 BOOL ret;
44
45 if(TestResults[i].ExpectedWinsta == NULL)
46 {
47 trace("Process should have failed to initialize\n");
48 return;
49 }
50
51 IsGUIThread(TRUE);
52
53 hdesktop = GetThreadDesktop(GetCurrentThreadId());
54 hwinsta = GetProcessWindowStation();
55
56 ret = GetUserObjectInformationW( hwinsta, UOI_NAME, buffer, sizeof(buffer), &size );
57 ok(ret == TRUE, "ret = %d\n", ret);
58 ok(wcscmp(buffer, TestResults[i].ExpectedWinsta) == 0, "Wrong winsta %S insted of %S\n", buffer, TestResults[i].ExpectedWinsta);
59
60 ret = GetUserObjectInformationW( hdesktop, UOI_NAME, buffer, sizeof(buffer), &size );
61 ok(ret == TRUE, "ret = %d\n", ret);
62 ok(wcscmp(buffer, TestResults[i].ExpectedDesktp) == 0, "Wrong desktop %S insted of %S\n", buffer, TestResults[i].ExpectedDesktp);
63 }
64
65 void test_CreateProcessWithDesktop(int i, char *argv0, char* Desktop, DWORD expectedExitCode)
66 {
67 STARTUPINFOA startup;
68 char path[MAX_PATH];
69 BOOL ret;
70 DWORD ExitCode;
71 PROCESS_INFORMATION pi;
72
73 memset( &startup, 0, sizeof(startup) );
74 startup.cb = sizeof(startup);
75 startup.dwFlags = STARTF_USESHOWWINDOW;
76 startup.wShowWindow = SW_SHOWNORMAL;
77 startup.lpDesktop = Desktop;
78
79 sprintf( path, "%s desktop %u", argv0, i );
80 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
81 ok( ret, "%d: CreateProcess '%s' failed err %d.\n", i, path, (int)GetLastError() );
82 WaitForSingleObject (pi.hProcess, INFINITE);
83 ret = GetExitCodeProcess(pi.hProcess, &ExitCode);
84 ok(ret > 0 , "%d: GetExitCodeProcess failed\n", i);
85
86 /* the exit code varies from version to version */
87 /* xp returns error 128 and 7 returns STATUS_DLL_INIT_FAILED */
88 if(ExitCode == 128) ExitCode = STATUS_DLL_INIT_FAILED;
89
90 ok(ExitCode == expectedExitCode, "%d: expected error 0x%x in child process got 0x%x\n", i, (int)expectedExitCode, (int)ExitCode);
91
92 CloseHandle(pi.hProcess);
93 }
94
95 HWINSTA CreateInheritableWinsta(WCHAR* name, ACCESS_MASK dwDesiredAccess, BOOL inheritable)
96 {
97 SECURITY_ATTRIBUTES sa;
98 sa.nLength = sizeof(sa);
99 sa.lpSecurityDescriptor = NULL;
100 sa.bInheritHandle = inheritable;
101 return CreateWindowStationW(name, 0, dwDesiredAccess, &sa );
102 }
103
104 HDESK CreateInheritableDesktop(WCHAR* name, ACCESS_MASK dwDesiredAccess, BOOL inheritable)
105 {
106 SECURITY_ATTRIBUTES sa;
107 sa.nLength = sizeof(sa);
108 sa.lpSecurityDescriptor = NULL;
109 sa.bInheritHandle = inheritable;
110 return CreateDesktopW(name, NULL, NULL, 0, dwDesiredAccess, &sa );
111 }
112
113 void Test_InitialDesktop(char *argv0)
114 {
115 HWINSTA hwinsta = NULL, hwinstaInitial;
116 HDESK hdesktop = NULL;
117 BOOL ret;
118
119 hwinstaInitial = GetProcessWindowStation();
120
121 test_CreateProcessWithDesktop(0, argv0, NULL, 0);
122 test_CreateProcessWithDesktop(1, argv0, "Default", 0);
123 test_CreateProcessWithDesktop(2, argv0, "WinSta0\\Default", 0);
124 test_CreateProcessWithDesktop(3, argv0, "Winlogon", STATUS_DLL_INIT_FAILED);
125 test_CreateProcessWithDesktop(4, argv0, "WinSta0/Default", STATUS_DLL_INIT_FAILED);
126 test_CreateProcessWithDesktop(5, argv0, "NonExistantDesktop", STATUS_DLL_INIT_FAILED);
127 test_CreateProcessWithDesktop(6, argv0, "NonExistantWinsta\\NonExistantDesktop", STATUS_DLL_INIT_FAILED);
128
129 hwinsta = CreateInheritableWinsta(L"TestWinsta", WINSTA_ALL_ACCESS, TRUE);
130 ok(hwinsta!=NULL, "CreateWindowStation failed\n");
131 ret = SetProcessWindowStation(hwinsta);
132 ok(ret != 0, "SetProcessWindowStation failed\n");
133 hdesktop = CreateInheritableDesktop(L"TestDesktop", DESKTOP_ALL_ACCESS, TRUE);
134 ok(hdesktop!=NULL, "CreateDesktop failed\n");
135
136 test_CreateProcessWithDesktop(7, argv0, NULL, 0);
137 test_CreateProcessWithDesktop(8, argv0, "TestWinsta\\TestDesktop", 0);
138 test_CreateProcessWithDesktop(8, argv0, "NonExistantWinsta\\NonExistantDesktop", STATUS_DLL_INIT_FAILED);
139
140 ret = SetProcessWindowStation(hwinstaInitial);
141 ok(ret != 0, "SetProcessWindowStation failed\n");
142
143 ret = CloseDesktop(hdesktop);
144 ok(ret != 0, "CloseDesktop failed\n");
145
146 ret = CloseWindowStation(hwinsta);
147 ok(ret != 0, "CloseWindowStation failed\n");
148 }
149
150 void Test_OpenInputDesktop()
151 {
152 HDESK hDeskInput ,hDeskInput2;
153 HDESK hDeskInitial;
154 BOOL ret;
155 HWINSTA hwinsta = NULL, hwinstaInitial;
156 DWORD err;
157
158 hDeskInput = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
159 ok(hDeskInput != NULL, "OpenInputDesktop failed\n");
160 hDeskInitial = GetThreadDesktop( GetCurrentThreadId() );
161 ok(hDeskInitial != NULL, "GetThreadDesktop failed\n");
162 ok(hDeskInput != hDeskInitial, "OpenInputDesktop returned thread desktop\n");
163
164 hDeskInput2 = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
165 ok(hDeskInput2 != NULL, "Second call to OpenInputDesktop failed\n");
166 ok(hDeskInput2 != hDeskInput, "Second call to OpenInputDesktop returned same handle\n");
167
168 ok(CloseDesktop(hDeskInput2) != 0, "CloseDesktop failed\n");
169
170 ret = SetThreadDesktop(hDeskInput);
171 ok(ret == TRUE, "SetThreadDesktop for input desktop failed\n");
172
173 ret = SetThreadDesktop(hDeskInitial);
174 ok(ret == TRUE, "SetThreadDesktop for initial desktop failed\n");
175
176 ok(CloseDesktop(hDeskInput) != 0, "CloseDesktop failed\n");
177
178 /* Try calling OpenInputDesktop after switching to a new winsta */
179 hwinstaInitial = GetProcessWindowStation();
180 ok(hwinstaInitial != 0, "GetProcessWindowStation failed\n");
181
182 hwinsta = CreateWindowStationW(L"TestWinsta", 0, WINSTA_ALL_ACCESS, NULL);
183 ok(hwinsta != 0, "CreateWindowStationW failed\n");
184
185 ret = SetProcessWindowStation(hwinsta);
186 ok(ret != 0, "SetProcessWindowStation failed\n");
187
188 hDeskInput = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
189 ok(hDeskInput == 0, "OpenInputDesktop should fail\n");
190
191 err = GetLastError();
192 ok(err == ERROR_INVALID_FUNCTION, "Got last error: %lu\n", err);
193
194 ret = SetProcessWindowStation(hwinstaInitial);
195 ok(ret != 0, "SetProcessWindowStation failed\n");
196
197 ret = CloseWindowStation(hwinsta);
198 ok(ret != 0, "CloseWindowStation failed\n");
199
200 }
201
202 static HWINSTA open_winsta(PCWSTR winstaName, DWORD *error)
203 {
204 HWINSTA hwinsta;
205 SetLastError(0xfeedf00d);
206 hwinsta = OpenWindowStationW(winstaName, FALSE, WINSTA_ALL_ACCESS);
207 *error = GetLastError();
208 return hwinsta;
209 }
210
211 static HWINSTA create_winsta(PCWSTR winstaName, DWORD *error)
212 {
213 HWINSTA hwinsta;
214 SetLastError(0xfeedf00d);
215 hwinsta = CreateWindowStationW(winstaName, 0, WINSTA_ALL_ACCESS, NULL);
216 *error = GetLastError();
217 return hwinsta;
218 }
219
220 static HDESK open_desk(PCWSTR deskName, DWORD *error)
221 {
222 HDESK hdesk;
223 SetLastError(0xfeedf00d);
224 hdesk = OpenDesktopW(deskName, 0, FALSE, DESKTOP_ALL_ACCESS);
225 *error = GetLastError();
226 return hdesk;
227 }
228
229 static HDESK create_desk(PCWSTR deskName, DWORD *error)
230 {
231 HDESK hdesk;
232 SetLastError(0xfeedf00d);
233 hdesk = CreateDesktopW(deskName, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL);
234 *error = GetLastError();
235 return hdesk;
236 }
237
238 static void Test_References(void)
239 {
240 PCWSTR winstaName = L"RefTestWinsta";
241 PCWSTR deskName = L"RefTestDesktop";
242 HWINSTA hwinsta;
243 HWINSTA hwinsta2;
244 HWINSTA hwinstaProcess;
245 DWORD error;
246 NTSTATUS status;
247 OBJECT_BASIC_INFORMATION objectInfo = { 0 };
248 HDESK hdesk;
249 BOOL ret;
250 ULONG baseRefs;
251
252 #define check_ref(handle, hdlcnt, ptrcnt) \
253 status = NtQueryObject(handle, ObjectBasicInformation, &objectInfo, sizeof(objectInfo), NULL); \
254 ok(status == STATUS_SUCCESS, "status = %lx\n", status); \
255 ok(objectInfo.HandleCount == (hdlcnt), "HandleCount = %lx\n", objectInfo.HandleCount); \
256 ok(objectInfo.PointerCount == (ptrcnt), "PointerCount = %lx\n", objectInfo.PointerCount);
257
258 /* Winsta shouldn't exist */
259 hwinsta = open_winsta(winstaName, &error);
260 ok(hwinsta == NULL && error == ERROR_FILE_NOT_FOUND, "Got %p, %lu\n", hwinsta, error);
261
262 /* Create it -- we get 1/4 instead of 1/3 because Winstas are kept in a list */
263 hwinsta = create_winsta(winstaName, &error);
264 ok(hwinsta != NULL && error == NO_ERROR, "Got %p, %lu\n", hwinsta, error);
265 check_ref(hwinsta, 1, 4);
266 baseRefs = objectInfo.PointerCount;
267 ok(baseRefs == 4, "Window station initially has %lu references, expected 4\n", baseRefs);
268 check_ref(hwinsta, 1, baseRefs);
269
270 /* Open a second handle */
271 hwinsta2 = open_winsta(winstaName, &error);
272 ok(hwinsta2 != NULL && error == 0xfeedf00d, "Got %p, %lu\n", hwinsta, error);
273 check_ref(hwinsta, 2, baseRefs + 1);
274
275 /* Close second handle -- back to 1/4 */
276 ret = CloseHandle(hwinsta2);
277 ok(ret == TRUE, "ret = %d\n", ret);
278 check_ref(hwinsta, 1, baseRefs);
279
280 /* Same game but using CloseWindowStation */
281 hwinsta2 = open_winsta(winstaName, &error);
282 ok(hwinsta2 != NULL && error == 0xfeedf00d, "Got %p, %lu\n", hwinsta, error);
283 check_ref(hwinsta, 2, baseRefs + 1);
284 ret = CloseWindowStation(hwinsta2);
285 ok(ret == TRUE, "ret = %d\n", ret);
286 check_ref(hwinsta, 1, baseRefs);
287
288 /* Set it as the process Winsta */
289 hwinstaProcess = GetProcessWindowStation();
290 SetProcessWindowStation(hwinsta);
291 check_ref(hwinsta, 2, baseRefs + 2);
292
293 /* Create a desktop. It takes a reference */
294 hdesk = create_desk(deskName, &error);
295 ok(hdesk != NULL && error == 0xfeedf00d, "Got %p, %lu\n", hdesk, error);
296 check_ref(hwinsta, 2, baseRefs + 3);
297
298 /* CloseHandle fails, must use CloseDesktop */
299 ret = CloseHandle(hdesk);
300 ok(ret == FALSE, "ret = %d\n", ret);
301 check_ref(hwinsta, 2, baseRefs + 3);
302 ret = CloseDesktop(hdesk);
303 ok(ret == TRUE, "ret = %d\n", ret);
304 check_ref(hwinsta, 2, baseRefs + 2); // 2/7 on Win7?
305
306 /* Desktop no longer exists */
307 hdesk = open_desk(deskName, &error);
308 ok(hdesk == NULL && error == ERROR_FILE_NOT_FOUND, "Got %p, %lu\n", hdesk, error);
309 check_ref(hwinsta, 2, baseRefs + 2);
310
311 /* Restore the original process Winsta */
312 SetProcessWindowStation(hwinstaProcess);
313 check_ref(hwinsta, 1, baseRefs);
314
315 /* Close our last handle */
316 ret = CloseHandle(hwinsta);
317 ok(ret == TRUE, "ret = %d\n", ret);
318
319 /* Winsta no longer exists */
320 hwinsta = open_winsta(winstaName, &error);
321 ok(hwinsta == NULL && error == ERROR_FILE_NOT_FOUND, "Got %p, %lu\n", hwinsta, error);
322
323 /* Create the Winsta again, and close it while there's still a desktop */
324 hwinsta = create_winsta(winstaName, &error);
325 ok(hwinsta != NULL && error == NO_ERROR, "Got %p, %lu\n", hwinsta, error);
326 check_ref(hwinsta, 1, baseRefs);
327 hwinstaProcess = GetProcessWindowStation();
328 SetProcessWindowStation(hwinsta);
329 check_ref(hwinsta, 2, baseRefs + 2);
330
331 hdesk = create_desk(deskName, &error);
332 ok(hdesk != NULL && error == 0xfeedf00d, "Got %p, %lu\n", hdesk, error);
333 check_ref(hwinsta, 2, baseRefs + 3);
334
335 /* The reference from the desktop is still there, hence 1/5 */
336 SetProcessWindowStation(hwinstaProcess);
337 check_ref(hwinsta, 1, baseRefs + 1);
338 ret = CloseHandle(hwinsta);
339 ok(ret == TRUE, "ret = %d\n", ret);
340 hwinsta = open_winsta(winstaName, &error);
341 ok(hwinsta == NULL && error == ERROR_FILE_NOT_FOUND, "Got %p, %lu\n", hwinsta, error);
342 }
343
344 START_TEST(desktop)
345 {
346 char **test_argv;
347 int argc = winetest_get_mainargs( &test_argv );
348
349 /* this program tests some cases that a child application fails to initialize */
350 /* to test this behaviour properly we have to disable error messages */
351 //SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
352
353 if (argc >= 3)
354 {
355 unsigned int arg;
356 /* Child process. */
357 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
358 do_InitialDesktop_child( arg );
359 return;
360 }
361
362 Test_InitialDesktop(test_argv[0]);
363 Test_OpenInputDesktop();
364 Test_References();
365 }