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
11 #include <ndk/obfuncs.h>
14 WCHAR
* ExpectedWinsta
;
15 WCHAR
* ExpectedDesktp
;
18 struct test_info TestResults
[] =
20 {L
"WinSta0",L
"Default"},
21 {L
"WinSta0",L
"Default"},
24 {L
"WinSta0",L
"Default"},
29 {L
"WinSta0",L
"Default"},
33 {L
"TestWinsta", L
"TestDesktop"},
35 {L
"WinSta0",L
"Default"},
39 void do_InitialDesktop_child(int i
)
47 if (TestResults
[i
].ExpectedWinsta
== NULL
)
48 ok(FALSE
, "%d: Process should have failed to initialize\n", i
);
52 hdesktop
= GetThreadDesktop(GetCurrentThreadId());
53 hwinsta
= GetProcessWindowStation();
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
);
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
);
68 void test_CreateProcessWithDesktop(int i
, char *argv0
, char* Desktop
, DWORD expectedExitCode
)
74 PROCESS_INFORMATION pi
;
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
;
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
);
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
;
93 ok(ExitCode
== expectedExitCode
, "%d: expected error 0x%x in child process got 0x%x\n", i
, (int)expectedExitCode
, (int)ExitCode
);
95 CloseHandle(pi
.hProcess
);
98 HWINSTA
CreateInheritableWinsta(WCHAR
* name
, ACCESS_MASK dwDesiredAccess
, BOOL inheritable
, DWORD
*error
)
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();
111 HDESK
CreateInheritableDesktop(WCHAR
* name
, ACCESS_MASK dwDesiredAccess
, BOOL inheritable
, DWORD
*error
)
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();
124 void Test_InitialDesktop(char *argv0
)
126 HWINSTA hwinsta
= NULL
, hwinstaInitial
;
127 HDESK hdesktop
= NULL
;
131 hwinstaInitial
= GetProcessWindowStation();
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
);
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
);
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
);
159 ret
= SetProcessWindowStation(hwinstaInitial
);
160 ok(ret
!= FALSE
, "SetProcessWindowStation failed\n");
162 ret
= CloseDesktop(hdesktop
);
163 ok(ret
!= FALSE
, "CloseDesktop failed\n");
165 ret
= CloseWindowStation(hwinsta
);
166 ok(ret
!= FALSE
, "CloseWindowStation failed\n");
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
);
177 test_CreateProcessWithDesktop(15, argv0
, NULL
, 0);
178 test_CreateProcessWithDesktop(16, "TestDesktop", NULL
, 0 /*ERROR_ACCESS_DENIED*/);
180 ret
= SetProcessWindowStation(hwinstaInitial
);
181 ok(ret
!= FALSE
, "SetProcessWindowStation failed\n");
183 ret
= CloseDesktop(hdesktop
);
184 ok(ret
!= FALSE
, "CloseDesktop failed\n");
186 ret
= CloseWindowStation(hwinsta
);
187 ok(ret
!= FALSE
, "CloseWindowStation failed\n");
191 void Test_OpenInputDesktop()
193 HDESK hDeskInput
,hDeskInput2
;
196 HWINSTA hwinsta
= NULL
, hwinstaInitial
;
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");
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");
209 ok(CloseDesktop(hDeskInput2
) != 0, "CloseDesktop failed\n");
211 ret
= SetThreadDesktop(hDeskInput
);
212 ok(ret
== TRUE
, "SetThreadDesktop for input desktop failed\n");
214 ret
= SetThreadDesktop(hDeskInitial
);
215 ok(ret
== TRUE
, "SetThreadDesktop for initial desktop failed\n");
217 ok(CloseDesktop(hDeskInput
) != 0, "CloseDesktop failed\n");
219 /* Try calling OpenInputDesktop after switching to a new winsta */
220 hwinstaInitial
= GetProcessWindowStation();
221 ok(hwinstaInitial
!= 0, "GetProcessWindowStation failed\n");
223 hwinsta
= CreateWindowStationW(L
"TestWinsta", 0, WINSTA_ALL_ACCESS
, NULL
);
224 ok(hwinsta
!= 0, "CreateWindowStationW failed\n");
226 ret
= SetProcessWindowStation(hwinsta
);
227 ok(ret
!= FALSE
, "SetProcessWindowStation failed\n");
229 hDeskInput
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
230 ok(hDeskInput
== 0, "OpenInputDesktop should fail\n");
232 err
= GetLastError();
233 ok(err
== ERROR_INVALID_FUNCTION
, "Got last error: %lu\n", err
);
235 ret
= SetProcessWindowStation(hwinstaInitial
);
236 ok(ret
!= FALSE
, "SetProcessWindowStation failed\n");
238 ret
= CloseWindowStation(hwinsta
);
239 ok(ret
!= FALSE
, "CloseWindowStation failed\n");
243 static HWINSTA
open_winsta(PCWSTR winstaName
, DWORD
*error
)
246 SetLastError(0xfeedf00d);
247 hwinsta
= OpenWindowStationW(winstaName
, FALSE
, WINSTA_ALL_ACCESS
);
248 *error
= GetLastError();
252 static HWINSTA
create_winsta(PCWSTR winstaName
, DWORD
*error
)
255 SetLastError(0xfeedf00d);
256 hwinsta
= CreateWindowStationW(winstaName
, 0, WINSTA_ALL_ACCESS
, NULL
);
257 *error
= GetLastError();
261 static HDESK
open_desk(PCWSTR deskName
, DWORD
*error
)
264 SetLastError(0xfeedf00d);
265 hdesk
= OpenDesktopW(deskName
, 0, FALSE
, DESKTOP_ALL_ACCESS
);
266 *error
= GetLastError();
270 static HDESK
create_desk(PCWSTR deskName
, DWORD
*error
)
273 SetLastError(0xfeedf00d);
274 hdesk
= CreateDesktopW(deskName
, NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
275 *error
= GetLastError();
279 static void Test_References(void)
281 PCWSTR winstaName
= L
"RefTestWinsta";
282 PCWSTR deskName
= L
"RefTestDesktop";
285 HWINSTA hwinstaProcess
;
288 OBJECT_BASIC_INFORMATION objectInfo
= { 0 };
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));
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
);
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
);
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);
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
);
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
);
330 /* Set it as the process Winsta */
331 hwinstaProcess
= GetProcessWindowStation();
332 SetProcessWindowStation(hwinsta
);
333 check_ref(hwinsta
, 2, baseRefs
+ 2);
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);
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?
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);
353 /* Restore the original process Winsta */
354 SetProcessWindowStation(hwinstaProcess
);
355 check_ref(hwinsta
, 1, baseRefs
);
357 /* Close our last handle */
358 ret
= CloseHandle(hwinsta
);
359 ok(ret
== TRUE
, "ret = %d\n", ret
);
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
);
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);
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);
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
);
385 /* Test references by SetThreadDesktop */
386 hdesk1
= GetThreadDesktop(GetCurrentThreadId());
387 ok (hdesk1
!= hdesk
, "Expected the new desktop not to be the thread desktop\n");
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
);
394 SetThreadDesktop(hdesk
);
395 check_ref(hdesk
, 1, baseRefs
+ 1);
396 ok (GetThreadDesktop(GetCurrentThreadId()) == hdesk
, "Expected GetThreadDesktop to return hdesk\n");
398 SetThreadDesktop(hdesk1
);
399 check_ref(hdesk
, 1, baseRefs
);
400 ok (GetThreadDesktop(GetCurrentThreadId()) == hdesk1
, "Expected GetThreadDesktop to return hdesk1\n");
406 int argc
= winetest_get_mainargs( &test_argv
);
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 );
416 sscanf (test_argv
[2], "%d", (unsigned int *) &arg
);
417 do_InitialDesktop_child( arg
);
421 Test_InitialDesktop(test_argv
[0]);
422 Test_OpenInputDesktop();