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
9 #define WIN32_NO_STATUS
15 #include <user32testhelpers.h>
16 #include <ndk/umtypes.h>
17 #include <ndk/obfuncs.h>
19 #define DESKTOP_ALL_ACCESS 0x01ff
22 WCHAR
* ExpectedWinsta
;
23 WCHAR
* ExpectedDesktp
;
26 struct test_info TestResults
[] = {{L
"WinSta0",L
"Default"},
27 {L
"WinSta0",L
"Default"},
28 {L
"WinSta0",L
"Default"},
33 {L
"WinSta0",L
"Default"},
34 {L
"TestWinsta", L
"TestDesktop"},
37 void do_InitialDesktop_child(int i
)
45 if(TestResults
[i
].ExpectedWinsta
== NULL
)
47 trace("Process should have failed to initialize\n");
53 hdesktop
= GetThreadDesktop(GetCurrentThreadId());
54 hwinsta
= GetProcessWindowStation();
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
);
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
);
65 void test_CreateProcessWithDesktop(int i
, char *argv0
, char* Desktop
, DWORD expectedExitCode
)
71 PROCESS_INFORMATION pi
;
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
;
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
);
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
;
90 ok(ExitCode
== expectedExitCode
, "%d: expected error 0x%x in child process got 0x%x\n", i
, (int)expectedExitCode
, (int)ExitCode
);
92 CloseHandle(pi
.hProcess
);
95 HWINSTA
CreateInheritableWinsta(WCHAR
* name
, ACCESS_MASK dwDesiredAccess
, BOOL inheritable
)
97 SECURITY_ATTRIBUTES sa
;
98 sa
.nLength
= sizeof(sa
);
99 sa
.lpSecurityDescriptor
= NULL
;
100 sa
.bInheritHandle
= inheritable
;
101 return CreateWindowStationW(name
, 0, dwDesiredAccess
, &sa
);
104 HDESK
CreateInheritableDesktop(WCHAR
* name
, ACCESS_MASK dwDesiredAccess
, BOOL inheritable
)
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
);
113 void Test_InitialDesktop(char *argv0
)
115 HWINSTA hwinsta
= NULL
, hwinstaInitial
;
116 HDESK hdesktop
= NULL
;
119 hwinstaInitial
= GetProcessWindowStation();
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
);
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");
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
);
140 ret
= SetProcessWindowStation(hwinstaInitial
);
141 ok(ret
!= 0, "SetProcessWindowStation failed\n");
143 ret
= CloseDesktop(hdesktop
);
144 ok(ret
!= 0, "CloseDesktop failed\n");
146 ret
= CloseWindowStation(hwinsta
);
147 ok(ret
!= 0, "CloseWindowStation failed\n");
150 void Test_OpenInputDesktop()
152 HDESK hDeskInput
,hDeskInput2
;
155 HWINSTA hwinsta
= NULL
, hwinstaInitial
;
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");
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");
168 ok(CloseDesktop(hDeskInput2
) != 0, "CloseDesktop failed\n");
170 ret
= SetThreadDesktop(hDeskInput
);
171 ok(ret
== TRUE
, "SetThreadDesktop for input desktop failed\n");
173 ret
= SetThreadDesktop(hDeskInitial
);
174 ok(ret
== TRUE
, "SetThreadDesktop for initial desktop failed\n");
176 ok(CloseDesktop(hDeskInput
) != 0, "CloseDesktop failed\n");
178 /* Try calling OpenInputDesktop after switching to a new winsta */
179 hwinstaInitial
= GetProcessWindowStation();
180 ok(hwinstaInitial
!= 0, "GetProcessWindowStation failed\n");
182 hwinsta
= CreateWindowStationW(L
"TestWinsta", 0, WINSTA_ALL_ACCESS
, NULL
);
183 ok(hwinsta
!= 0, "CreateWindowStationW failed\n");
185 ret
= SetProcessWindowStation(hwinsta
);
186 ok(ret
!= 0, "SetProcessWindowStation failed\n");
188 hDeskInput
= OpenInputDesktop(0, FALSE
, DESKTOP_ALL_ACCESS
);
189 ok(hDeskInput
== 0, "OpenInputDesktop should fail\n");
191 err
= GetLastError();
192 ok(err
== ERROR_INVALID_FUNCTION
, "Got last error: %lu\n", err
);
194 ret
= SetProcessWindowStation(hwinstaInitial
);
195 ok(ret
!= 0, "SetProcessWindowStation failed\n");
197 ret
= CloseWindowStation(hwinsta
);
198 ok(ret
!= 0, "CloseWindowStation failed\n");
202 static HWINSTA
open_winsta(PCWSTR winstaName
, DWORD
*error
)
205 SetLastError(0xfeedf00d);
206 hwinsta
= OpenWindowStationW(winstaName
, FALSE
, WINSTA_ALL_ACCESS
);
207 *error
= GetLastError();
211 static HWINSTA
create_winsta(PCWSTR winstaName
, DWORD
*error
)
214 SetLastError(0xfeedf00d);
215 hwinsta
= CreateWindowStationW(winstaName
, 0, WINSTA_ALL_ACCESS
, NULL
);
216 *error
= GetLastError();
220 static HDESK
open_desk(PCWSTR deskName
, DWORD
*error
)
223 SetLastError(0xfeedf00d);
224 hdesk
= OpenDesktopW(deskName
, 0, FALSE
, DESKTOP_ALL_ACCESS
);
225 *error
= GetLastError();
229 static HDESK
create_desk(PCWSTR deskName
, DWORD
*error
)
232 SetLastError(0xfeedf00d);
233 hdesk
= CreateDesktopW(deskName
, NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
234 *error
= GetLastError();
238 static void Test_References(void)
240 PCWSTR winstaName
= L
"RefTestWinsta";
241 PCWSTR deskName
= L
"RefTestDesktop";
244 HWINSTA hwinstaProcess
;
247 OBJECT_BASIC_INFORMATION objectInfo
= { 0 };
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);
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
);
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
);
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);
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
);
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
);
288 /* Set it as the process Winsta */
289 hwinstaProcess
= GetProcessWindowStation();
290 SetProcessWindowStation(hwinsta
);
291 check_ref(hwinsta
, 2, baseRefs
+ 2);
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);
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?
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);
311 /* Restore the original process Winsta */
312 SetProcessWindowStation(hwinstaProcess
);
313 check_ref(hwinsta
, 1, baseRefs
);
315 /* Close our last handle */
316 ret
= CloseHandle(hwinsta
);
317 ok(ret
== TRUE
, "ret = %d\n", ret
);
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
);
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);
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);
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
);
347 int argc
= winetest_get_mainargs( &test_argv
);
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 );
357 sscanf (test_argv
[2], "%d", (unsigned int *) &arg
);
358 do_InitialDesktop_child( arg
);
362 Test_InitialDesktop(test_argv
[0]);
363 Test_OpenInputDesktop();