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