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 } 425