1 /* 2 * PROJECT: ReactOS Win32 Base API 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/kernel32/client/vdm.c 5 * PURPOSE: Virtual DOS Machines (VDM) Support 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <k32.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* TYPES **********************************************************************/ 17 18 #define BINARY_UNKNOWN (0) 19 #define BINARY_PE_EXE32 (1) 20 #define BINARY_PE_DLL32 (2) 21 #define BINARY_PE_EXE64 (3) 22 #define BINARY_PE_DLL64 (4) 23 #define BINARY_WIN16 (5) 24 #define BINARY_OS216 (6) 25 #define BINARY_DOS (7) 26 #define BINARY_UNIX_EXE (8) 27 #define BINARY_UNIX_LIB (9) 28 29 30 typedef enum _ENV_NAME_TYPE 31 { 32 EnvNameNotAPath = 1, 33 EnvNameSinglePath , 34 EnvNameMultiplePath 35 } ENV_NAME_TYPE; 36 37 typedef struct _ENV_INFO 38 { 39 ENV_NAME_TYPE NameType; 40 ULONG NameLength; 41 PWCHAR Name; 42 } ENV_INFO, *PENV_INFO; 43 44 /* GLOBALS ********************************************************************/ 45 46 #define ENV_NAME_ENTRY(type, name) \ 47 {(type), _ARRAYSIZE(name) - 1, (name)} 48 49 static ENV_INFO BasepEnvNameType[] = 50 { 51 ENV_NAME_ENTRY(EnvNameMultiplePath, L"PATH"), 52 ENV_NAME_ENTRY(EnvNameSinglePath , L"WINDIR"), 53 ENV_NAME_ENTRY(EnvNameSinglePath , L"SYSTEMROOT"), 54 ENV_NAME_ENTRY(EnvNameMultiplePath, L"TEMP"), 55 ENV_NAME_ENTRY(EnvNameMultiplePath, L"TMP"), 56 }; 57 58 static UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com"); 59 static UNICODE_STRING BaseDotPifSuffixName = RTL_CONSTANT_STRING(L".pif"); 60 static UNICODE_STRING BaseDotExeSuffixName = RTL_CONSTANT_STRING(L".exe"); 61 62 /* FUNCTIONS ******************************************************************/ 63 64 ULONG 65 WINAPI 66 BaseIsDosApplication(IN PUNICODE_STRING PathName, 67 IN NTSTATUS Status) 68 { 69 UNICODE_STRING String; 70 71 /* Is it a .com? */ 72 String.Length = BaseDotComSuffixName.Length; 73 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)]; 74 if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return BINARY_TYPE_COM; 75 76 /* Is it a .pif? */ 77 String.Length = BaseDotPifSuffixName.Length; 78 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)]; 79 if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return BINARY_TYPE_PIF; 80 81 /* Is it an exe? */ 82 String.Length = BaseDotExeSuffixName.Length; 83 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)]; 84 if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return BINARY_TYPE_EXE; 85 86 return 0; 87 } 88 89 NTSTATUS 90 WINAPI 91 BaseCheckVDM(IN ULONG BinaryType, 92 IN PCWCH ApplicationName, 93 IN PCWCH CommandLine, 94 IN PCWCH CurrentDirectory, 95 IN PANSI_STRING AnsiEnvironment, 96 IN PBASE_API_MESSAGE ApiMessage, 97 IN OUT PULONG iTask, 98 IN DWORD CreationFlags, 99 IN LPSTARTUPINFOW StartupInfo, 100 IN HANDLE hUserToken OPTIONAL) 101 { 102 NTSTATUS Status; 103 PBASE_CHECK_VDM CheckVdm = &ApiMessage->Data.CheckVDMRequest; 104 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; 105 PWCHAR CurrentDir = NULL; 106 PWCHAR ShortAppName = NULL; 107 PWCHAR ShortCurrentDir = NULL; 108 ULONG Length; 109 PCHAR AnsiCmdLine = NULL; 110 PCHAR AnsiAppName = NULL; 111 PCHAR AnsiCurDirectory = NULL; 112 PCHAR AnsiDesktop = NULL; 113 PCHAR AnsiTitle = NULL; 114 PCHAR AnsiReserved = NULL; 115 STARTUPINFOA AnsiStartupInfo; 116 ULONG NumStrings = 5; 117 118 /* Parameters validation */ 119 if (ApplicationName == NULL || CommandLine == NULL) 120 { 121 return STATUS_INVALID_PARAMETER; 122 } 123 124 /* Trim leading whitespace from ApplicationName */ 125 while (*ApplicationName == L' ' || *ApplicationName == L'\t') 126 ++ApplicationName; 127 128 /* Calculate the size of the short application name */ 129 Length = GetShortPathNameW(ApplicationName, NULL, 0); 130 if (Length == 0) 131 { 132 Status = STATUS_OBJECT_PATH_INVALID; 133 goto Cleanup; 134 } 135 136 /* Allocate memory for the short application name */ 137 ShortAppName = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 138 HEAP_ZERO_MEMORY, 139 Length * sizeof(WCHAR)); 140 if (!ShortAppName) 141 { 142 Status = STATUS_NO_MEMORY; 143 goto Cleanup; 144 } 145 146 /* Get the short application name */ 147 if (GetShortPathNameW(ApplicationName, ShortAppName, Length) == 0) 148 { 149 /* Try to determine which error occurred */ 150 switch (GetLastError()) 151 { 152 case ERROR_NOT_ENOUGH_MEMORY: 153 { 154 Status = STATUS_NO_MEMORY; 155 break; 156 } 157 158 case ERROR_INVALID_PARAMETER: 159 { 160 Status = STATUS_INVALID_PARAMETER; 161 break; 162 } 163 164 default: 165 { 166 Status = STATUS_OBJECT_PATH_INVALID; 167 } 168 } 169 170 goto Cleanup; 171 } 172 173 /* Trim leading whitespace from CommandLine */ 174 while (*CommandLine == L' ' || *CommandLine == L'\t') 175 ++CommandLine; 176 177 /* 178 * CommandLine is usually formatted as: 'ApplicationName param0 ...'. 179 * So we want to strip the first token (ApplicationName) from it. 180 * Two cases are in fact possible: 181 * - either the first token is indeed ApplicationName, so we just skip it; 182 * - or the first token is not exactly ApplicationName, because it happened 183 * that somebody else already preprocessed CommandLine. Therefore we 184 * suppose that the first token corresponds to an application name and 185 * we skip it. Care should be taken when quotes are present in this token. 186 */ 187 if (*CommandLine) 188 { 189 /* The first part of CommandLine should be the ApplicationName... */ 190 Length = wcslen(ApplicationName); 191 if (Length <= wcslen(CommandLine) && 192 _wcsnicmp(ApplicationName, CommandLine, Length) == 0) 193 { 194 /* Skip it */ 195 CommandLine += Length; 196 } 197 /* 198 * ... but it is not, however we still have a token. We suppose that 199 * it corresponds to some sort of application name, so we skip it too. 200 */ 201 else 202 { 203 /* Get rid of the first token. We stop when we see whitespace. */ 204 while (*CommandLine && !(*CommandLine == L' ' || *CommandLine == L'\t')) 205 { 206 if (*CommandLine == L'\"') 207 { 208 /* We enter a quoted part, skip it */ 209 ++CommandLine; 210 while (*CommandLine && *CommandLine++ != L'\"') ; 211 } 212 else 213 { 214 /* Go to the next character */ 215 ++CommandLine; 216 } 217 } 218 } 219 } 220 221 /* 222 * Trim remaining whitespace from CommandLine that may be 223 * present between the application name and the parameters. 224 */ 225 while (*CommandLine == L' ' || *CommandLine == L'\t') 226 ++CommandLine; 227 228 /* Get the current directory */ 229 if (CurrentDirectory == NULL) 230 { 231 /* Allocate memory for the current directory path */ 232 Length = GetCurrentDirectoryW(0, NULL); 233 CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 234 HEAP_ZERO_MEMORY, 235 Length * sizeof(WCHAR)); 236 if (CurrentDir == NULL) 237 { 238 Status = STATUS_NO_MEMORY; 239 goto Cleanup; 240 } 241 242 /* Get the current directory */ 243 GetCurrentDirectoryW(Length, CurrentDir); 244 CurrentDirectory = CurrentDir; 245 } 246 247 /* Calculate the size of the short current directory path */ 248 Length = GetShortPathNameW(CurrentDirectory, NULL, 0); 249 250 /* Allocate memory for the short current directory path */ 251 ShortCurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 252 HEAP_ZERO_MEMORY, 253 Length * sizeof(WCHAR)); 254 if (!ShortCurrentDir) 255 { 256 Status = STATUS_NO_MEMORY; 257 goto Cleanup; 258 } 259 260 /* Get the short current directory path */ 261 if (!GetShortPathNameW(CurrentDirectory, ShortCurrentDir, Length)) 262 { 263 /* Try to determine which error occurred */ 264 switch (GetLastError()) 265 { 266 case ERROR_NOT_ENOUGH_MEMORY: 267 { 268 Status = STATUS_NO_MEMORY; 269 break; 270 } 271 272 case ERROR_INVALID_PARAMETER: 273 { 274 Status = STATUS_INVALID_PARAMETER; 275 break; 276 } 277 278 default: 279 { 280 Status = STATUS_OBJECT_PATH_INVALID; 281 } 282 } 283 goto Cleanup; 284 } 285 286 /* Setup the input parameters */ 287 CheckVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 288 CheckVdm->BinaryType = BinaryType; 289 CheckVdm->CodePage = CP_ACP; 290 CheckVdm->dwCreationFlags = CreationFlags; 291 CheckVdm->CurDrive = CurrentDirectory[0] - L'A'; 292 CheckVdm->CmdLen = wcslen(CommandLine) + 1; 293 CheckVdm->AppLen = wcslen(ShortAppName) + 1; 294 CheckVdm->PifLen = 0; // TODO: PIF file support! 295 CheckVdm->CurDirectoryLen = wcslen(ShortCurrentDir) + 1; 296 CheckVdm->EnvLen = AnsiEnvironment->Length; 297 CheckVdm->DesktopLen = (StartupInfo->lpDesktop != NULL) ? (wcslen(StartupInfo->lpDesktop) + 1) : 0; 298 CheckVdm->TitleLen = (StartupInfo->lpTitle != NULL) ? (wcslen(StartupInfo->lpTitle) + 1) : 0; 299 CheckVdm->ReservedLen = (StartupInfo->lpReserved != NULL) ? (wcslen(StartupInfo->lpReserved) + 1) : 0; 300 301 if (StartupInfo->dwFlags & STARTF_USESTDHANDLES) 302 { 303 /* Set the standard handles */ 304 CheckVdm->StdIn = StartupInfo->hStdInput; 305 CheckVdm->StdOut = StartupInfo->hStdOutput; 306 CheckVdm->StdErr = StartupInfo->hStdError; 307 } 308 309 /* Allocate memory for the ANSI strings */ 310 // We need to add the newline characters '\r\n' to the command line 311 AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen + 2); 312 AnsiAppName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->AppLen); 313 AnsiCurDirectory = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CurDirectoryLen); 314 if (StartupInfo->lpDesktop) 315 AnsiDesktop = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 316 HEAP_ZERO_MEMORY, 317 CheckVdm->DesktopLen); 318 if (StartupInfo->lpTitle) 319 AnsiTitle = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 320 HEAP_ZERO_MEMORY, 321 CheckVdm->TitleLen); 322 if (StartupInfo->lpReserved) 323 AnsiReserved = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 324 HEAP_ZERO_MEMORY, 325 CheckVdm->ReservedLen); 326 327 if (!AnsiCmdLine 328 || !AnsiAppName 329 || !AnsiCurDirectory 330 || (StartupInfo->lpDesktop && !AnsiDesktop) 331 || (StartupInfo->lpTitle && !AnsiTitle) 332 || (StartupInfo->lpReserved && !AnsiReserved)) 333 { 334 Status = STATUS_NO_MEMORY; 335 goto Cleanup; 336 } 337 338 /* Convert the command line into an ANSI string */ 339 WideCharToMultiByte(CP_ACP, 340 0, 341 CommandLine, 342 CheckVdm->CmdLen, 343 AnsiCmdLine, 344 CheckVdm->CmdLen, 345 NULL, 346 NULL); 347 /* Add the needed newline and NULL-terminate */ 348 CheckVdm->CmdLen--; // Rewind back to the NULL character 349 AnsiCmdLine[CheckVdm->CmdLen++] = '\r'; 350 AnsiCmdLine[CheckVdm->CmdLen++] = '\n'; 351 AnsiCmdLine[CheckVdm->CmdLen++] = 0; 352 353 /* Convert the short application name into an ANSI string */ 354 WideCharToMultiByte(CP_ACP, 355 0, 356 ShortAppName, 357 CheckVdm->AppLen, 358 AnsiAppName, 359 CheckVdm->AppLen, 360 NULL, 361 NULL); 362 363 /* Convert the short current directory path into an ANSI string */ 364 WideCharToMultiByte(CP_ACP, 365 0, 366 ShortCurrentDir, 367 CheckVdm->CurDirectoryLen, 368 AnsiCurDirectory, 369 CheckVdm->CurDirectoryLen, 370 NULL, 371 NULL); 372 373 if (StartupInfo->lpDesktop) 374 { 375 /* Convert the desktop name into an ANSI string */ 376 WideCharToMultiByte(CP_ACP, 377 0, 378 StartupInfo->lpDesktop, 379 CheckVdm->DesktopLen, 380 AnsiDesktop, 381 CheckVdm->DesktopLen, 382 NULL, 383 NULL); 384 NumStrings++; 385 } 386 387 if (StartupInfo->lpTitle) 388 { 389 /* Convert the title into an ANSI string */ 390 WideCharToMultiByte(CP_ACP, 391 0, 392 StartupInfo->lpTitle, 393 CheckVdm->TitleLen, 394 AnsiTitle, 395 CheckVdm->TitleLen, 396 NULL, 397 NULL); 398 NumStrings++; 399 } 400 401 if (StartupInfo->lpReserved) 402 { 403 /* Convert the reserved value into an ANSI string */ 404 WideCharToMultiByte(CP_ACP, 405 0, 406 StartupInfo->lpReserved, 407 CheckVdm->ReservedLen, 408 AnsiReserved, 409 CheckVdm->ReservedLen, 410 NULL, 411 NULL); 412 NumStrings++; 413 } 414 415 /* Fill the ANSI startup info structure */ 416 RtlCopyMemory(&AnsiStartupInfo, StartupInfo, sizeof(AnsiStartupInfo)); 417 AnsiStartupInfo.lpReserved = AnsiReserved; 418 AnsiStartupInfo.lpDesktop = AnsiDesktop; 419 AnsiStartupInfo.lpTitle = AnsiTitle; 420 421 /* Allocate the capture buffer */ 422 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings, 423 CheckVdm->CmdLen 424 + CheckVdm->AppLen 425 + CheckVdm->PifLen 426 + CheckVdm->CurDirectoryLen 427 + CheckVdm->DesktopLen 428 + CheckVdm->TitleLen 429 + CheckVdm->ReservedLen 430 + CheckVdm->EnvLen 431 + sizeof(*CheckVdm->StartupInfo)); 432 if (CaptureBuffer == NULL) 433 { 434 Status = STATUS_NO_MEMORY; 435 goto Cleanup; 436 } 437 438 /* Capture the command line */ 439 CsrCaptureMessageBuffer(CaptureBuffer, 440 AnsiCmdLine, 441 CheckVdm->CmdLen, 442 (PVOID*)&CheckVdm->CmdLine); 443 444 /* Capture the application name */ 445 CsrCaptureMessageBuffer(CaptureBuffer, 446 AnsiAppName, 447 CheckVdm->AppLen, 448 (PVOID*)&CheckVdm->AppName); 449 450 CheckVdm->PifFile = NULL; // TODO: PIF file support! 451 452 /* Capture the current directory */ 453 CsrCaptureMessageBuffer(CaptureBuffer, 454 AnsiCurDirectory, 455 CheckVdm->CurDirectoryLen, 456 (PVOID*)&CheckVdm->CurDirectory); 457 458 /* Capture the environment */ 459 CsrCaptureMessageBuffer(CaptureBuffer, 460 AnsiEnvironment->Buffer, 461 CheckVdm->EnvLen, 462 (PVOID*)&CheckVdm->Env); 463 464 /* Capture the startup info structure */ 465 CsrCaptureMessageBuffer(CaptureBuffer, 466 &AnsiStartupInfo, 467 sizeof(*CheckVdm->StartupInfo), 468 (PVOID*)&CheckVdm->StartupInfo); 469 470 if (StartupInfo->lpDesktop) 471 { 472 /* Capture the desktop name */ 473 CsrCaptureMessageBuffer(CaptureBuffer, 474 AnsiDesktop, 475 CheckVdm->DesktopLen, 476 (PVOID*)&CheckVdm->Desktop); 477 } 478 else CheckVdm->Desktop = NULL; 479 480 if (StartupInfo->lpTitle) 481 { 482 /* Capture the title */ 483 CsrCaptureMessageBuffer(CaptureBuffer, 484 AnsiTitle, 485 CheckVdm->TitleLen, 486 (PVOID*)&CheckVdm->Title); 487 } 488 else CheckVdm->Title = NULL; 489 490 if (StartupInfo->lpReserved) 491 { 492 /* Capture the reserved parameter */ 493 CsrCaptureMessageBuffer(CaptureBuffer, 494 AnsiReserved, 495 CheckVdm->ReservedLen, 496 (PVOID*)&CheckVdm->Reserved); 497 } 498 else CheckVdm->Reserved = NULL; 499 500 /* Send the message to CSRSS */ 501 Status = CsrClientCallServer((PCSR_API_MESSAGE)ApiMessage, 502 CaptureBuffer, 503 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCheckVDM), 504 sizeof(*CheckVdm)); 505 506 /* Write back the task ID */ 507 *iTask = CheckVdm->iTask; 508 509 Cleanup: 510 511 /* Free the ANSI strings */ 512 if (AnsiCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine); 513 if (AnsiAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName); 514 if (AnsiCurDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory); 515 if (AnsiDesktop) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop); 516 if (AnsiTitle) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle); 517 if (AnsiReserved) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved); 518 519 /* Free the capture buffer */ 520 if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); 521 522 /* Free the current directory, if it was allocated here, and its short path */ 523 if (ShortCurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir); 524 if (CurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir); 525 526 /* Free the short app name */ 527 if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName); 528 529 return Status; 530 } 531 532 BOOL 533 WINAPI 534 BaseUpdateVDMEntry(IN ULONG UpdateIndex, 535 IN OUT PHANDLE WaitHandle, 536 IN ULONG IndexInfo, 537 IN ULONG BinaryType) 538 { 539 BASE_API_MESSAGE ApiMessage; 540 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest; 541 542 /* Check what update is being sent */ 543 switch (UpdateIndex) 544 { 545 /* VDM is being undone */ 546 case VdmEntryUndo: 547 { 548 /* Tell the server how far we had gotten along */ 549 UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle); 550 UpdateVdmEntry->VDMCreationState = IndexInfo; 551 break; 552 } 553 554 /* VDM is ready with a new process handle */ 555 case VdmEntryUpdateProcess: 556 { 557 /* Send it the process handle */ 558 UpdateVdmEntry->VDMProcessHandle = *WaitHandle; 559 UpdateVdmEntry->iTask = IndexInfo; 560 break; 561 } 562 } 563 564 /* Also check what kind of binary this is for the console handle */ 565 if (BinaryType == BINARY_TYPE_WOW) 566 { 567 /* Magic value for 16-bit apps */ 568 UpdateVdmEntry->ConsoleHandle = (HANDLE)-1; 569 } 570 else if (UpdateVdmEntry->iTask) 571 { 572 /* No handle for true VDM */ 573 UpdateVdmEntry->ConsoleHandle = NULL; 574 } 575 else 576 { 577 /* Otherwise, use the regular console handle */ 578 UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 579 } 580 581 /* Finally write the index and binary type */ 582 UpdateVdmEntry->EntryIndex = UpdateIndex; 583 UpdateVdmEntry->BinaryType = BinaryType; 584 585 /* Send the message to CSRSS */ 586 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 587 NULL, 588 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepUpdateVDMEntry), 589 sizeof(*UpdateVdmEntry)); 590 if (!NT_SUCCESS(ApiMessage.Status)) 591 { 592 /* Handle failure */ 593 BaseSetLastNTError(ApiMessage.Status); 594 return FALSE; 595 } 596 597 /* If this was an update, CSRSS returns a new wait handle */ 598 if (UpdateIndex == VdmEntryUpdateProcess) 599 { 600 /* Return it to the caller */ 601 *WaitHandle = UpdateVdmEntry->WaitObjectForParent; 602 } 603 604 /* We made it */ 605 return TRUE; 606 } 607 608 BOOL 609 WINAPI 610 BaseCheckForVDM(IN HANDLE ProcessHandle, 611 OUT LPDWORD ExitCode) 612 { 613 NTSTATUS Status; 614 EVENT_BASIC_INFORMATION EventBasicInfo; 615 BASE_API_MESSAGE ApiMessage; 616 PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest; 617 618 /* It's VDM if the process is actually a wait handle (an event) */ 619 Status = NtQueryEvent(ProcessHandle, 620 EventBasicInformation, 621 &EventBasicInfo, 622 sizeof(EventBasicInfo), 623 NULL); 624 if (!NT_SUCCESS(Status)) return FALSE; 625 626 /* Setup the input parameters */ 627 GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 628 GetVdmExitCode->hParent = ProcessHandle; 629 630 /* Call CSRSS */ 631 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 632 NULL, 633 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMExitCode), 634 sizeof(*GetVdmExitCode)); 635 if (!NT_SUCCESS(Status)) return FALSE; 636 637 /* Get the exit code from the reply */ 638 *ExitCode = GetVdmExitCode->ExitCode; 639 return TRUE; 640 } 641 642 BOOL 643 WINAPI 644 BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved, 645 IN ULONG DosSeqId, 646 IN ULONG BinaryType, 647 IN PUNICODE_STRING CmdLineString, 648 OUT PULONG VdmSize) 649 { 650 WCHAR Buffer[MAX_PATH]; 651 WCHAR CommandLine[MAX_PATH * 2]; 652 ULONG Length; 653 654 /* Clear the buffer in case we fail */ 655 CmdLineString->Buffer = 0; 656 657 /* Always return the same size: 16 Mb */ 658 *VdmSize = 0x1000000; 659 660 /* Get the system directory */ 661 Length = GetSystemDirectoryW(Buffer, MAX_PATH); 662 if (!(Length) || (Length >= MAX_PATH)) 663 { 664 /* Eliminate no path or path too big */ 665 SetLastError(ERROR_INVALID_NAME); 666 return FALSE; 667 } 668 669 /* Check if this is VDM with a DOS Sequence ID */ 670 if (DosSeqId) 671 { 672 /* 673 * Build the VDM string for it: 674 * -i%lx : Gives the DOS Sequence ID; 675 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM. 676 */ 677 _snwprintf(CommandLine, 678 ARRAYSIZE(CommandLine), 679 L"\"%s\\ntvdm.exe\" -i%lx %s%c", 680 Buffer, 681 DosSeqId, 682 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w", 683 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' '); 684 } 685 else 686 { 687 /* 688 * Build the string for it without the DOS Sequence ID: 689 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM. 690 */ 691 _snwprintf(CommandLine, 692 ARRAYSIZE(CommandLine), 693 L"\"%s\\ntvdm.exe\" %s%c", 694 Buffer, 695 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w", 696 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' '); 697 } 698 699 /* Create the actual string */ 700 return RtlCreateUnicodeString(CmdLineString, CommandLine); 701 } 702 703 ENV_NAME_TYPE 704 WINAPI 705 BaseGetEnvNameType_U(IN PWCHAR Name, 706 IN ULONG NameLength) 707 { 708 PENV_INFO EnvInfo; 709 ENV_NAME_TYPE NameType; 710 ULONG i; 711 712 /* Start by assuming the environment variable doesn't describe paths */ 713 NameType = EnvNameNotAPath; 714 715 /* Loop all the environment names */ 716 for (i = 0; i < ARRAYSIZE(BasepEnvNameType); i++) 717 { 718 /* Get this entry */ 719 EnvInfo = &BasepEnvNameType[i]; 720 721 /* Check if it matches the name */ 722 if ((EnvInfo->NameLength == NameLength) && 723 (_wcsnicmp(EnvInfo->Name, Name, NameLength) == 0)) 724 { 725 /* It does, return the type */ 726 NameType = EnvInfo->NameType; 727 break; 728 } 729 } 730 731 return NameType; 732 } 733 734 BOOL 735 NTAPI 736 BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment, 737 OUT PANSI_STRING AnsiEnv, 738 OUT PUNICODE_STRING UnicodeEnv) 739 { 740 #define IS_ALPHA(x) \ 741 ( ((x) >= L'A' && (x) <= L'Z') || ((x) >= L'a' && (x) <= L'z') ) 742 743 // From lib/rtl/path.c : 744 // Can be put in some .h ?? 745 #define IS_PATH_SEPARATOR(x) ((x) == L'\\' || (x) == L'/') 746 747 BOOL Success = FALSE; 748 NTSTATUS Status; 749 ULONG RegionSize, EnvironmentSize = 0; 750 PWCHAR Environment, NewEnvironment = NULL; 751 ENV_NAME_TYPE NameType; 752 ULONG NameLength, NumChars, Remaining; 753 PWCHAR SourcePtr, DestPtr, StartPtr; 754 755 /* Make sure we have both strings */ 756 if (!AnsiEnv || !UnicodeEnv) 757 { 758 /* Fail */ 759 SetLastError(ERROR_INVALID_PARAMETER); 760 return FALSE; 761 } 762 763 /* Check if an environment was passed in */ 764 if (!lpEnvironment) 765 { 766 /* Nope, create one */ 767 Status = RtlCreateEnvironment(TRUE, &Environment); 768 if (!NT_SUCCESS(Status)) goto Cleanup; 769 } 770 else 771 { 772 /* Use the one we got */ 773 Environment = lpEnvironment; 774 } 775 776 /* Do we have something now ? */ 777 if (!Environment) 778 { 779 /* Still not, bail out */ 780 SetLastError(ERROR_BAD_ENVIRONMENT); 781 goto Cleanup; 782 } 783 784 /* 785 * Count how much space the whole environment takes. The environment block is 786 * doubly NULL-terminated (NULL from last string and final NULL terminator). 787 */ 788 SourcePtr = Environment; 789 while (!(*SourcePtr++ == UNICODE_NULL && *SourcePtr == UNICODE_NULL)) 790 ++EnvironmentSize; 791 EnvironmentSize += 2; // Add the two terminating NULLs 792 793 /* 794 * Allocate a new copy large enough to hold all the environment with paths 795 * in their short form. Since the short form of a path can be a bit longer 796 * than its long form, for example in the case where characters that are 797 * invalid in the 8.3 representation are present in the long path name: 798 * 'C:\\a+b' --> 'C:\\A_B~1', or: 799 * 'C:\\a b' --> 'C:\\AB2761~1' (with checksum inserted), 800 * we suppose that the possible total number of extra characters needed to 801 * convert the long paths into their short form is at most equal to MAX_PATH. 802 */ 803 RegionSize = (EnvironmentSize + MAX_PATH) * sizeof(WCHAR); 804 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 805 (PVOID*)&NewEnvironment, 806 0, 807 &RegionSize, 808 MEM_COMMIT, 809 PAGE_READWRITE); 810 if (!NT_SUCCESS(Status)) 811 { 812 /* We failed, bail out */ 813 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 814 NewEnvironment = NULL; 815 goto Cleanup; 816 } 817 818 /* Parse the environment block */ 819 Remaining = MAX_PATH - 2; // '-2': remove the last two NULLs. FIXME: is it really needed?? 820 SourcePtr = Environment; 821 DestPtr = NewEnvironment; 822 823 /* Loop through all the environment strings */ 824 while (*SourcePtr != UNICODE_NULL) 825 { 826 /* 827 * 1. Check the type of the environment variable and copy its name. 828 */ 829 830 /* Regular environment variable */ 831 if (*SourcePtr != L'=') 832 { 833 StartPtr = SourcePtr; 834 835 /* Copy the environment variable name, including the '=' */ 836 while (*SourcePtr != UNICODE_NULL) 837 { 838 *DestPtr++ = *SourcePtr; 839 if (*SourcePtr++ == L'=') break; 840 } 841 842 /* Guess the type of the environment variable */ 843 NameType = BaseGetEnvNameType_U(StartPtr, SourcePtr - StartPtr - 1); 844 } 845 /* 'Current directory' environment variable (i.e. of '=X:=' form) */ 846 else // if (*SourcePtr == L'=') 847 { 848 /* First assume we have a possibly malformed environment variable */ 849 NameType = EnvNameNotAPath; 850 851 /* Check for a valid 'Current directory' environment variable */ 852 if (IS_ALPHA(SourcePtr[1]) && SourcePtr[2] == L':' && SourcePtr[3] == L'=') 853 { 854 /* 855 * Small optimization: convert the path to short form only if 856 * the current directory is not the root directory (i.e. not 857 * of the '=X:=Y:\' form), otherwise just do a simple copy. 858 */ 859 if ( wcslen(SourcePtr) >= ARRAYSIZE("=X:=Y:\\")-1 && 860 !( IS_ALPHA(SourcePtr[4]) && SourcePtr[5] == L':' && 861 IS_PATH_SEPARATOR(SourcePtr[6]) && SourcePtr[7] == UNICODE_NULL ) ) 862 { 863 NameType = EnvNameSinglePath; 864 865 /* Copy the '=X:=' prefix */ 866 *DestPtr++ = SourcePtr[0]; 867 *DestPtr++ = SourcePtr[1]; 868 *DestPtr++ = SourcePtr[2]; 869 *DestPtr++ = SourcePtr[3]; 870 SourcePtr += 4; 871 } 872 } 873 else 874 { 875 /* 876 * Invalid stuff starting with '=', i.e.: 877 * =? (with '?' not being a letter) 878 * =X??? (with '?' not being ":=" and not followed by something longer than 3 characters) 879 * =X:=??? (with '?' not being "X:\\") 880 * 881 * 'NameType' is already set to 'EnvNameNotAPath'. 882 */ 883 } 884 } 885 886 887 /* 888 * 2. Copy the environment value and perform conversions accordingly. 889 */ 890 891 if (NameType == EnvNameNotAPath) 892 { 893 /* Copy everything, including the NULL terminator */ 894 do 895 { 896 *DestPtr++ = *SourcePtr; 897 } while (*SourcePtr++ != UNICODE_NULL); 898 } 899 else if (NameType == EnvNameSinglePath) 900 { 901 /* Convert the path to its short form */ 902 NameLength = wcslen(SourcePtr); 903 NumChars = GetShortPathNameW(SourcePtr, DestPtr, NameLength + 1 + Remaining); 904 if (NumChars == 0 || NumChars > NameLength + Remaining) 905 { 906 /* If the conversion failed, just copy the original value */ 907 RtlCopyMemory(DestPtr, SourcePtr, NameLength * sizeof(WCHAR)); 908 NumChars = NameLength; 909 } 910 DestPtr += NumChars; 911 if (NumChars > NameLength) 912 Remaining -= (NumChars - NameLength); 913 914 SourcePtr += NameLength; 915 916 /* Copy the NULL terminator */ 917 *DestPtr++ = *SourcePtr++; 918 } 919 else // if (NameType == EnvNameMultiplePath) 920 { 921 WCHAR Delimiter; 922 923 /* Loop through the list of paths (delimited by ';') and convert each path to its short form */ 924 do 925 { 926 /* Copy any trailing ';' before going to the next path */ 927 while (*SourcePtr == L';') 928 { 929 *DestPtr++ = *SourcePtr++; 930 } 931 932 StartPtr = SourcePtr; 933 934 /* Find the next path list delimiter or the NULL terminator */ 935 while (*SourcePtr != UNICODE_NULL && *SourcePtr != L';') 936 { 937 ++SourcePtr; 938 } 939 Delimiter = *SourcePtr; 940 941 NameLength = SourcePtr - StartPtr; 942 if (NameLength) 943 { 944 /* 945 * Temporarily replace the possible path list delimiter by NULL. 946 * 'lpEnvironment' must point to a read+write memory buffer! 947 */ 948 *SourcePtr = UNICODE_NULL; 949 950 NumChars = GetShortPathNameW(StartPtr, DestPtr, NameLength + 1 + Remaining); 951 if ( NumChars == 0 || 952 (Delimiter == L';' ? NumChars > NameLength + Remaining 953 : NumChars > NameLength /* + Remaining ?? */) ) 954 { 955 /* If the conversion failed, just copy the original value */ 956 RtlCopyMemory(DestPtr, StartPtr, NameLength * sizeof(WCHAR)); 957 NumChars = NameLength; 958 } 959 DestPtr += NumChars; 960 if (NumChars > NameLength) 961 Remaining -= (NumChars - NameLength); 962 963 /* If removed, restore the path list delimiter in the source environment value and copy it */ 964 if (Delimiter != UNICODE_NULL) 965 { 966 *SourcePtr = Delimiter; 967 *DestPtr++ = *SourcePtr++; 968 } 969 } 970 } while (*SourcePtr != UNICODE_NULL); 971 972 /* Copy the NULL terminator */ 973 *DestPtr++ = *SourcePtr++; 974 } 975 } 976 977 /* NULL-terminate the environment block */ 978 *DestPtr++ = UNICODE_NULL; 979 980 /* Initialize the Unicode string to hold it */ 981 RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, 982 (DestPtr - NewEnvironment) * sizeof(WCHAR)); 983 UnicodeEnv->Length = UnicodeEnv->MaximumLength; 984 985 /* Create its ANSI version */ 986 Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE); 987 if (!NT_SUCCESS(Status)) 988 { 989 /* Set last error if conversion failure */ 990 BaseSetLastNTError(Status); 991 } 992 else 993 { 994 /* Everything went okay, so return success */ 995 Success = TRUE; 996 NewEnvironment = NULL; 997 } 998 999 Cleanup: 1000 /* Cleanup path starts here, start by destroying the environment copy */ 1001 if (!lpEnvironment && Environment) RtlDestroyEnvironment(Environment); 1002 1003 /* See if we are here due to failure */ 1004 if (NewEnvironment) 1005 { 1006 /* Initialize the paths to be empty */ 1007 RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0); 1008 RtlInitEmptyAnsiString(AnsiEnv, NULL, 0); 1009 1010 /* Free the environment copy */ 1011 RegionSize = 0; 1012 Status = NtFreeVirtualMemory(NtCurrentProcess(), 1013 (PVOID*)&NewEnvironment, 1014 &RegionSize, 1015 MEM_RELEASE); 1016 ASSERT(NT_SUCCESS(Status)); 1017 } 1018 1019 /* Return the result */ 1020 return Success; 1021 } 1022 1023 BOOL 1024 NTAPI 1025 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv, 1026 IN PUNICODE_STRING UnicodeEnv) 1027 { 1028 ULONG Dummy = 0; 1029 1030 /* Clear the ANSI buffer since Rtl creates this for us */ 1031 if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv); 1032 1033 /* The Unicode buffer is build by hand, though */ 1034 if (UnicodeEnv->Buffer) 1035 { 1036 /* So clear it through the API */ 1037 NtFreeVirtualMemory(NtCurrentProcess(), 1038 (PVOID*)&UnicodeEnv->Buffer, 1039 &Dummy, 1040 MEM_RELEASE); 1041 } 1042 1043 /* All done */ 1044 return TRUE; 1045 } 1046 1047 1048 /* Check whether a file is an OS/2 or a very old Windows executable 1049 * by testing on import of KERNEL. 1050 * 1051 * FIXME: is reading the module imports the only way of discerning 1052 * old Windows binaries from OS/2 ones ? At least it seems so... 1053 */ 1054 static DWORD WINAPI 1055 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne) 1056 { 1057 DWORD CurPos; 1058 LPWORD modtab = NULL; 1059 LPSTR nametab = NULL; 1060 DWORD Read, Ret; 1061 int i; 1062 1063 Ret = BINARY_OS216; 1064 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); 1065 1066 /* read modref table */ 1067 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1068 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) || 1069 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) || 1070 (Read != (DWORD)ne->ne_cmod * sizeof(WORD))) 1071 { 1072 goto broken; 1073 } 1074 1075 /* read imported names table */ 1076 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1077 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) || 1078 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) || 1079 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab)) 1080 { 1081 goto broken; 1082 } 1083 1084 for(i = 0; i < ne->ne_cmod; i++) 1085 { 1086 LPSTR module; 1087 module = &nametab[modtab[i]]; 1088 if(!strncmp(&module[1], "KERNEL", module[0])) 1089 { 1090 /* very old windows file */ 1091 Ret = BINARY_WIN16; 1092 goto done; 1093 } 1094 } 1095 1096 broken: 1097 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n"); 1098 1099 done: 1100 HeapFree(GetProcessHeap(), 0, modtab); 1101 HeapFree(GetProcessHeap(), 0, nametab); 1102 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN); 1103 return Ret; 1104 } 1105 1106 static DWORD WINAPI 1107 InternalGetBinaryType(HANDLE hFile) 1108 { 1109 union 1110 { 1111 struct 1112 { 1113 unsigned char magic[4]; 1114 unsigned char ignored[12]; 1115 unsigned short type; 1116 } elf; 1117 struct 1118 { 1119 unsigned long magic; 1120 unsigned long cputype; 1121 unsigned long cpusubtype; 1122 unsigned long filetype; 1123 } macho; 1124 IMAGE_DOS_HEADER mz; 1125 } Header; 1126 char magic[4]; 1127 DWORD Read; 1128 1129 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1130 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) || 1131 (Read != sizeof(Header)))) 1132 { 1133 return BINARY_UNKNOWN; 1134 } 1135 1136 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic))) 1137 { 1138 /* FIXME: we don't bother to check byte order, architecture, etc. */ 1139 switch(Header.elf.type) 1140 { 1141 case 2: 1142 return BINARY_UNIX_EXE; 1143 case 3: 1144 return BINARY_UNIX_LIB; 1145 } 1146 return BINARY_UNKNOWN; 1147 } 1148 1149 /* Mach-o File with Endian set to Big Endian or Little Endian*/ 1150 if(Header.macho.magic == 0xFEEDFACE || 1151 Header.macho.magic == 0xCEFAEDFE) 1152 { 1153 switch(Header.macho.filetype) 1154 { 1155 case 0x8: 1156 /* MH_BUNDLE */ 1157 return BINARY_UNIX_LIB; 1158 } 1159 return BINARY_UNKNOWN; 1160 } 1161 1162 /* Not ELF, try DOS */ 1163 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE) 1164 { 1165 /* We do have a DOS image so we will now try to seek into 1166 * the file by the amount indicated by the field 1167 * "Offset to extended header" and read in the 1168 * "magic" field information at that location. 1169 * This will tell us if there is more header information 1170 * to read or not. 1171 */ 1172 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1173 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) || 1174 (Read != sizeof(magic)))) 1175 { 1176 return BINARY_DOS; 1177 } 1178 1179 /* Reading the magic field succeeded so 1180 * we will try to determine what type it is. 1181 */ 1182 if(!memcmp(magic, "PE\0\0", sizeof(magic))) 1183 { 1184 IMAGE_FILE_HEADER FileHeader; 1185 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) || 1186 (Read != sizeof(IMAGE_FILE_HEADER))) 1187 { 1188 return BINARY_DOS; 1189 } 1190 1191 /* FIXME - detect 32/64 bit */ 1192 1193 if(FileHeader.Characteristics & IMAGE_FILE_DLL) 1194 return BINARY_PE_DLL32; 1195 return BINARY_PE_EXE32; 1196 } 1197 1198 if(!memcmp(magic, "NE", 2)) 1199 { 1200 /* This is a Windows executable (NE) header. This can 1201 * mean either a 16-bit OS/2 or a 16-bit Windows or even a 1202 * DOS program (running under a DOS extender). To decide 1203 * which, we'll have to read the NE header. 1204 */ 1205 IMAGE_OS2_HEADER ne; 1206 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) || 1207 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) || 1208 (Read != sizeof(IMAGE_OS2_HEADER))) 1209 { 1210 /* Couldn't read header, so abort. */ 1211 return BINARY_DOS; 1212 } 1213 1214 switch(ne.ne_exetyp) 1215 { 1216 case 2: 1217 return BINARY_WIN16; 1218 case 5: 1219 return BINARY_DOS; 1220 default: 1221 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne); 1222 } 1223 } 1224 return BINARY_DOS; 1225 } 1226 return BINARY_UNKNOWN; 1227 } 1228 1229 /* 1230 * @implemented 1231 */ 1232 BOOL 1233 WINAPI 1234 GetBinaryTypeW ( 1235 LPCWSTR lpApplicationName, 1236 LPDWORD lpBinaryType 1237 ) 1238 { 1239 HANDLE hFile; 1240 DWORD BinType; 1241 1242 if(!lpApplicationName || !lpBinaryType) 1243 { 1244 SetLastError(ERROR_INVALID_PARAMETER); 1245 return FALSE; 1246 } 1247 1248 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL, 1249 OPEN_EXISTING, 0, 0); 1250 if(hFile == INVALID_HANDLE_VALUE) 1251 { 1252 return FALSE; 1253 } 1254 1255 BinType = InternalGetBinaryType(hFile); 1256 CloseHandle(hFile); 1257 1258 switch(BinType) 1259 { 1260 case BINARY_UNKNOWN: 1261 { 1262 WCHAR *dot; 1263 1264 /* 1265 * guess from filename 1266 */ 1267 if(!(dot = wcsrchr(lpApplicationName, L'.'))) 1268 { 1269 return FALSE; 1270 } 1271 if(!lstrcmpiW(dot, L".COM")) 1272 { 1273 *lpBinaryType = SCS_DOS_BINARY; 1274 return TRUE; 1275 } 1276 if(!lstrcmpiW(dot, L".PIF")) 1277 { 1278 *lpBinaryType = SCS_PIF_BINARY; 1279 return TRUE; 1280 } 1281 return FALSE; 1282 } 1283 case BINARY_PE_EXE32: 1284 case BINARY_PE_DLL32: 1285 { 1286 *lpBinaryType = SCS_32BIT_BINARY; 1287 return TRUE; 1288 } 1289 case BINARY_PE_EXE64: 1290 case BINARY_PE_DLL64: 1291 { 1292 *lpBinaryType = SCS_64BIT_BINARY; 1293 return TRUE; 1294 } 1295 case BINARY_WIN16: 1296 { 1297 *lpBinaryType = SCS_WOW_BINARY; 1298 return TRUE; 1299 } 1300 case BINARY_OS216: 1301 { 1302 *lpBinaryType = SCS_OS216_BINARY; 1303 return TRUE; 1304 } 1305 case BINARY_DOS: 1306 { 1307 *lpBinaryType = SCS_DOS_BINARY; 1308 return TRUE; 1309 } 1310 case BINARY_UNIX_EXE: 1311 case BINARY_UNIX_LIB: 1312 { 1313 return FALSE; 1314 } 1315 } 1316 1317 DPRINT1("Invalid binary type %lu returned!\n", BinType); 1318 return FALSE; 1319 } 1320 1321 /* 1322 * @implemented 1323 */ 1324 BOOL 1325 WINAPI 1326 GetBinaryTypeA(IN LPCSTR lpApplicationName, 1327 OUT LPDWORD lpBinaryType) 1328 { 1329 ANSI_STRING ApplicationNameString; 1330 UNICODE_STRING ApplicationNameW; 1331 BOOL StringAllocated = FALSE, Result; 1332 NTSTATUS Status; 1333 1334 RtlInitAnsiString(&ApplicationNameString, lpApplicationName); 1335 1336 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength) 1337 { 1338 StringAllocated = TRUE; 1339 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE); 1340 } 1341 else 1342 { 1343 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE); 1344 } 1345 1346 if (!NT_SUCCESS(Status)) 1347 { 1348 BaseSetLastNTError(Status); 1349 return FALSE; 1350 } 1351 1352 if (StringAllocated) 1353 { 1354 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType); 1355 RtlFreeUnicodeString(&ApplicationNameW); 1356 } 1357 else 1358 { 1359 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType); 1360 } 1361 1362 return Result; 1363 } 1364 1365 /* 1366 * @unimplemented 1367 */ 1368 BOOL 1369 WINAPI 1370 CmdBatNotification ( 1371 DWORD Unknown 1372 ) 1373 { 1374 STUB; 1375 return FALSE; 1376 } 1377 1378 /* 1379 * @implemented 1380 */ 1381 VOID 1382 WINAPI 1383 ExitVDM(BOOL IsWow, ULONG iWowTask) 1384 { 1385 BASE_API_MESSAGE ApiMessage; 1386 PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest; 1387 1388 /* Setup the input parameters */ 1389 ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1390 ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */ 1391 ExitVdm->WaitObjectForVDM = NULL; 1392 1393 /* Call CSRSS */ 1394 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1395 NULL, 1396 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM), 1397 sizeof(*ExitVdm)); 1398 1399 /* Close the returned wait object handle, if any */ 1400 if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL)) 1401 { 1402 CloseHandle(ExitVdm->WaitObjectForVDM); 1403 } 1404 } 1405 1406 /* 1407 * @implemented 1408 */ 1409 BOOL 1410 WINAPI 1411 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData) 1412 { 1413 BOOL Success = FALSE; 1414 NTSTATUS Status; 1415 BASE_API_MESSAGE ApiMessage; 1416 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest; 1417 PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest; 1418 PBASE_SET_REENTER_COUNT SetReenterCount = &ApiMessage.Data.SetReenterCountRequest; 1419 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; 1420 ULONG NumStrings = 0; 1421 1422 /* 1423 * Special case to test whether the VDM is the first one. 1424 */ 1425 if (CommandData == NULL) 1426 { 1427 /* Call CSRSS */ 1428 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1429 NULL, 1430 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM), 1431 sizeof(*IsFirstVdm)); 1432 if (!NT_SUCCESS(ApiMessage.Status)) 1433 { 1434 BaseSetLastNTError(ApiMessage.Status); 1435 return FALSE; 1436 } 1437 1438 /* Return TRUE if this is the first VDM */ 1439 return IsFirstVdm->FirstVDM; 1440 } 1441 1442 /* CommandData != NULL */ 1443 1444 /* 1445 * Special case to increment or decrement the reentrancy count. 1446 */ 1447 if ((CommandData->VDMState == VDM_INC_REENTER_COUNT) || 1448 (CommandData->VDMState == VDM_DEC_REENTER_COUNT)) 1449 { 1450 /* Setup the input parameters */ 1451 SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1452 SetReenterCount->fIncDec = CommandData->VDMState; 1453 1454 /* Call CSRSS */ 1455 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1456 NULL, 1457 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount), 1458 sizeof(*SetReenterCount)); 1459 if (!NT_SUCCESS(ApiMessage.Status)) 1460 { 1461 BaseSetLastNTError(ApiMessage.Status); 1462 return FALSE; 1463 } 1464 1465 return TRUE; 1466 } 1467 1468 /* 1469 * TODO! 1470 * Special case to retrieve or set WOW information. 1471 */ 1472 // TODO: if CommandData->VDMState & (VDM_LIST_WOW_PROCESSES | VDM_LIST_WOW_TASKS | VDM_ADD_WOW_TASK) 1473 // then call BasepGetNextVDMCommand in a simpler way! 1474 1475 /* 1476 * Regular case. 1477 */ 1478 1479 /* Clear the structure */ 1480 RtlZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand)); 1481 1482 /* Setup the input parameters */ 1483 GetNextVdmCommand->iTask = CommandData->TaskId; 1484 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1485 GetNextVdmCommand->CmdLen = CommandData->CmdLen; 1486 GetNextVdmCommand->AppLen = CommandData->AppLen; 1487 GetNextVdmCommand->PifLen = CommandData->PifLen; 1488 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen; 1489 GetNextVdmCommand->EnvLen = CommandData->EnvLen; 1490 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen; 1491 GetNextVdmCommand->TitleLen = CommandData->TitleLen; 1492 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen; 1493 GetNextVdmCommand->VDMState = CommandData->VDMState; 1494 1495 /* Count the number of strings */ 1496 if (CommandData->CmdLen) NumStrings++; 1497 if (CommandData->AppLen) NumStrings++; 1498 if (CommandData->PifLen) NumStrings++; 1499 if (CommandData->CurDirectoryLen) NumStrings++; 1500 if (CommandData->EnvLen) NumStrings++; 1501 if (CommandData->DesktopLen) NumStrings++; 1502 if (CommandData->TitleLen) NumStrings++; 1503 if (CommandData->ReservedLen) NumStrings++; 1504 1505 /* Allocate the capture buffer */ 1506 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1, 1507 GetNextVdmCommand->CmdLen 1508 + GetNextVdmCommand->AppLen 1509 + GetNextVdmCommand->PifLen 1510 + GetNextVdmCommand->CurDirectoryLen 1511 + GetNextVdmCommand->EnvLen 1512 + GetNextVdmCommand->DesktopLen 1513 + GetNextVdmCommand->TitleLen 1514 + GetNextVdmCommand->ReservedLen 1515 + sizeof(*GetNextVdmCommand->StartupInfo)); 1516 if (CaptureBuffer == NULL) 1517 { 1518 BaseSetLastNTError(STATUS_NO_MEMORY); 1519 goto Cleanup; 1520 } 1521 1522 /* Capture the data */ 1523 1524 CsrAllocateMessagePointer(CaptureBuffer, 1525 sizeof(*GetNextVdmCommand->StartupInfo), 1526 (PVOID*)&GetNextVdmCommand->StartupInfo); 1527 1528 if (CommandData->CmdLen) 1529 { 1530 CsrAllocateMessagePointer(CaptureBuffer, 1531 CommandData->CmdLen, 1532 (PVOID*)&GetNextVdmCommand->CmdLine); 1533 } 1534 1535 if (CommandData->AppLen) 1536 { 1537 CsrAllocateMessagePointer(CaptureBuffer, 1538 CommandData->AppLen, 1539 (PVOID*)&GetNextVdmCommand->AppName); 1540 } 1541 1542 if (CommandData->PifLen) 1543 { 1544 CsrAllocateMessagePointer(CaptureBuffer, 1545 CommandData->PifLen, 1546 (PVOID*)&GetNextVdmCommand->PifFile); 1547 } 1548 1549 if (CommandData->CurDirectoryLen) 1550 { 1551 CsrAllocateMessagePointer(CaptureBuffer, 1552 CommandData->CurDirectoryLen, 1553 (PVOID*)&GetNextVdmCommand->CurDirectory); 1554 } 1555 1556 if (CommandData->EnvLen) 1557 { 1558 CsrAllocateMessagePointer(CaptureBuffer, 1559 CommandData->EnvLen, 1560 (PVOID*)&GetNextVdmCommand->Env); 1561 } 1562 1563 if (CommandData->DesktopLen) 1564 { 1565 CsrAllocateMessagePointer(CaptureBuffer, 1566 CommandData->DesktopLen, 1567 (PVOID*)&GetNextVdmCommand->Desktop); 1568 } 1569 1570 if (CommandData->TitleLen) 1571 { 1572 CsrAllocateMessagePointer(CaptureBuffer, 1573 CommandData->TitleLen, 1574 (PVOID*)&GetNextVdmCommand->Title); 1575 } 1576 1577 if (CommandData->ReservedLen) 1578 { 1579 CsrAllocateMessagePointer(CaptureBuffer, 1580 CommandData->ReservedLen, 1581 (PVOID*)&GetNextVdmCommand->Reserved); 1582 } 1583 1584 while (TRUE) 1585 { 1586 /* Call CSRSS */ 1587 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1588 CaptureBuffer, 1589 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand), 1590 sizeof(*GetNextVdmCommand)); 1591 1592 /* Exit the waiting loop if we did not receive any event handle */ 1593 if (GetNextVdmCommand->WaitObjectForVDM == NULL) 1594 break; 1595 1596 /* Wait for the event to become signaled and try again */ 1597 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM, 1598 FALSE, NULL); 1599 if (Status != STATUS_SUCCESS) 1600 { 1601 /* Fail if we timed out, or if some other error happened */ 1602 BaseSetLastNTError(Status); 1603 goto Cleanup; 1604 } 1605 1606 /* Set the retry flag, clear the exit code, and retry a query */ 1607 GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY; 1608 GetNextVdmCommand->ExitCode = 0; 1609 } 1610 1611 if (!NT_SUCCESS(Status)) 1612 { 1613 if (Status == STATUS_INVALID_PARAMETER) 1614 { 1615 /* 1616 * One of the buffer lengths was less than required. Store the correct ones. 1617 * Note that the status code is not STATUS_BUFFER_TOO_SMALL as one would expect, 1618 * in order to keep compatibility with Windows 2003 BASESRV.DLL. 1619 */ 1620 CommandData->CmdLen = GetNextVdmCommand->CmdLen; 1621 CommandData->AppLen = GetNextVdmCommand->AppLen; 1622 CommandData->PifLen = GetNextVdmCommand->PifLen; 1623 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen; 1624 CommandData->EnvLen = GetNextVdmCommand->EnvLen; 1625 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen; 1626 CommandData->TitleLen = GetNextVdmCommand->TitleLen; 1627 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen; 1628 } 1629 else 1630 { 1631 /* Any other failure */ 1632 CommandData->CmdLen = 0; 1633 CommandData->AppLen = 0; 1634 CommandData->PifLen = 0; 1635 CommandData->CurDirectoryLen = 0; 1636 CommandData->EnvLen = 0; 1637 CommandData->DesktopLen = 0; 1638 CommandData->TitleLen = 0; 1639 CommandData->ReservedLen = 0; 1640 } 1641 1642 BaseSetLastNTError(Status); 1643 goto Cleanup; 1644 } 1645 1646 /* Write back the standard handles */ 1647 CommandData->StdIn = GetNextVdmCommand->StdIn; 1648 CommandData->StdOut = GetNextVdmCommand->StdOut; 1649 CommandData->StdErr = GetNextVdmCommand->StdErr; 1650 1651 /* Write back the startup info */ 1652 RtlMoveMemory(&CommandData->StartupInfo, 1653 GetNextVdmCommand->StartupInfo, 1654 sizeof(*GetNextVdmCommand->StartupInfo)); 1655 1656 if (CommandData->CmdLen) 1657 { 1658 /* Write back the command line */ 1659 RtlMoveMemory(CommandData->CmdLine, 1660 GetNextVdmCommand->CmdLine, 1661 GetNextVdmCommand->CmdLen); 1662 1663 /* Set the actual length */ 1664 CommandData->CmdLen = GetNextVdmCommand->CmdLen; 1665 } 1666 1667 if (CommandData->AppLen) 1668 { 1669 /* Write back the application name */ 1670 RtlMoveMemory(CommandData->AppName, 1671 GetNextVdmCommand->AppName, 1672 GetNextVdmCommand->AppLen); 1673 1674 /* Set the actual length */ 1675 CommandData->AppLen = GetNextVdmCommand->AppLen; 1676 } 1677 1678 if (CommandData->PifLen) 1679 { 1680 /* Write back the PIF file name */ 1681 RtlMoveMemory(CommandData->PifFile, 1682 GetNextVdmCommand->PifFile, 1683 GetNextVdmCommand->PifLen); 1684 1685 /* Set the actual length */ 1686 CommandData->PifLen = GetNextVdmCommand->PifLen; 1687 } 1688 1689 if (CommandData->CurDirectoryLen) 1690 { 1691 /* Write back the current directory */ 1692 RtlMoveMemory(CommandData->CurDirectory, 1693 GetNextVdmCommand->CurDirectory, 1694 GetNextVdmCommand->CurDirectoryLen); 1695 1696 /* Set the actual length */ 1697 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen; 1698 } 1699 1700 if (CommandData->EnvLen) 1701 { 1702 /* Write back the environment */ 1703 RtlMoveMemory(CommandData->Env, 1704 GetNextVdmCommand->Env, 1705 GetNextVdmCommand->EnvLen); 1706 1707 /* Set the actual length */ 1708 CommandData->EnvLen = GetNextVdmCommand->EnvLen; 1709 } 1710 1711 if (CommandData->DesktopLen) 1712 { 1713 /* Write back the desktop name */ 1714 RtlMoveMemory(CommandData->Desktop, 1715 GetNextVdmCommand->Desktop, 1716 GetNextVdmCommand->DesktopLen); 1717 1718 /* Set the actual length */ 1719 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen; 1720 } 1721 1722 if (CommandData->TitleLen) 1723 { 1724 /* Write back the title */ 1725 RtlMoveMemory(CommandData->Title, 1726 GetNextVdmCommand->Title, 1727 GetNextVdmCommand->TitleLen); 1728 1729 /* Set the actual length */ 1730 CommandData->TitleLen = GetNextVdmCommand->TitleLen; 1731 } 1732 1733 if (CommandData->ReservedLen) 1734 { 1735 /* Write back the reserved parameter */ 1736 RtlMoveMemory(CommandData->Reserved, 1737 GetNextVdmCommand->Reserved, 1738 GetNextVdmCommand->ReservedLen); 1739 1740 /* Set the actual length */ 1741 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen; 1742 } 1743 1744 /* Write the remaining output parameters */ 1745 CommandData->TaskId = GetNextVdmCommand->iTask; 1746 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags; 1747 CommandData->CodePage = GetNextVdmCommand->CodePage; 1748 CommandData->ExitCode = GetNextVdmCommand->ExitCode; 1749 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive; 1750 CommandData->VDMState = GetNextVdmCommand->VDMState; 1751 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat; 1752 1753 /* It was successful */ 1754 Success = TRUE; 1755 1756 Cleanup: 1757 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer); 1758 return Success; 1759 } 1760 1761 1762 /* 1763 * @implemented 1764 */ 1765 DWORD 1766 WINAPI 1767 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs) 1768 { 1769 BASE_API_MESSAGE ApiMessage; 1770 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest; 1771 PCSR_CAPTURE_BUFFER CaptureBuffer; 1772 1773 /* Allocate the capture buffer */ 1774 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs); 1775 if (CaptureBuffer == NULL) 1776 { 1777 BaseSetLastNTError(STATUS_NO_MEMORY); 1778 return 0; 1779 } 1780 1781 /* Setup the input parameters */ 1782 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs; 1783 CsrAllocateMessagePointer(CaptureBuffer, 1784 cchCurDirs, 1785 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs); 1786 1787 /* Call CSRSS */ 1788 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1789 CaptureBuffer, 1790 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs), 1791 sizeof(*VDMCurrentDirsRequest)); 1792 1793 /* Set the last error */ 1794 BaseSetLastNTError(ApiMessage.Status); 1795 1796 if (NT_SUCCESS(ApiMessage.Status)) 1797 { 1798 /* Copy the result */ 1799 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs); 1800 } 1801 1802 /* Free the capture buffer */ 1803 CsrFreeCaptureBuffer(CaptureBuffer); 1804 1805 /* Return the size if it was successful, or if the buffer was too small */ 1806 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL)) 1807 ? VDMCurrentDirsRequest->cchCurDirs : 0; 1808 } 1809 1810 1811 /* 1812 * @implemented (undocumented) 1813 */ 1814 BOOL 1815 WINAPI 1816 RegisterConsoleVDM(IN DWORD dwRegisterFlags, 1817 IN HANDLE hStartHardwareEvent, 1818 IN HANDLE hEndHardwareEvent, 1819 IN HANDLE hErrorHardwareEvent, 1820 IN DWORD dwUnusedVar, 1821 OUT LPDWORD lpVideoStateLength, 1822 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER* 1823 IN PVOID lpUnusedBuffer, 1824 IN DWORD dwUnusedBufferLength, 1825 IN COORD dwVDMBufferSize, 1826 OUT PVOID* lpVDMBuffer) 1827 { 1828 BOOL Success; 1829 CONSOLE_API_MESSAGE ApiMessage; 1830 PCONSOLE_REGISTERVDM RegisterVDMRequest = &ApiMessage.Data.RegisterVDMRequest; 1831 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; 1832 1833 /* Set up the data to send to the Console Server */ 1834 RegisterVDMRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1835 RegisterVDMRequest->RegisterFlags = dwRegisterFlags; 1836 1837 if (dwRegisterFlags != 0) 1838 { 1839 RegisterVDMRequest->StartHardwareEvent = hStartHardwareEvent; 1840 RegisterVDMRequest->EndHardwareEvent = hEndHardwareEvent; 1841 RegisterVDMRequest->ErrorHardwareEvent = hErrorHardwareEvent; 1842 1843 RegisterVDMRequest->VDMBufferSize = dwVDMBufferSize; 1844 1845 #if 0 1846 RegisterVDMRequest->UnusedBufferLength = dwUnusedBufferLength; 1847 1848 /* Allocate a Capture Buffer */ 1849 CaptureBuffer = CsrAllocateCaptureBuffer(1, dwUnusedBufferLength); 1850 if (CaptureBuffer == NULL) 1851 { 1852 DPRINT1("CsrAllocateCaptureBuffer failed!\n"); 1853 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1854 return FALSE; 1855 } 1856 1857 /* Capture the buffer to write */ 1858 CsrCaptureMessageBuffer(CaptureBuffer, 1859 (PVOID)lpUnusedBuffer, 1860 dwUnusedBufferLength, 1861 (PVOID*)&RegisterVDMRequest->UnusedBuffer); 1862 #endif 1863 } 1864 else 1865 { 1866 // CaptureBuffer = NULL; 1867 } 1868 1869 /* Call the server */ 1870 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1871 CaptureBuffer, 1872 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepRegisterVDM), 1873 sizeof(*RegisterVDMRequest)); 1874 1875 /* Check for success */ 1876 Success = NT_SUCCESS(ApiMessage.Status); 1877 1878 /* Release the capture buffer if needed */ 1879 if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); 1880 1881 /* Retrieve the results */ 1882 if (Success) 1883 { 1884 if (dwRegisterFlags != 0) 1885 { 1886 _SEH2_TRY 1887 { 1888 *lpVideoStateLength = RegisterVDMRequest->VideoStateLength; 1889 *lpVideoState = RegisterVDMRequest->VideoState; 1890 *lpVDMBuffer = RegisterVDMRequest->VDMBuffer; 1891 } 1892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1893 { 1894 SetLastError(ERROR_INVALID_ACCESS); 1895 Success = FALSE; 1896 } 1897 _SEH2_END; 1898 } 1899 } 1900 else 1901 { 1902 BaseSetLastNTError(ApiMessage.Status); 1903 } 1904 1905 /* Return success status */ 1906 return Success; 1907 } 1908 1909 1910 /* 1911 * @unimplemented 1912 */ 1913 BOOL 1914 WINAPI 1915 RegisterWowBaseHandlers ( 1916 DWORD Unknown0 1917 ) 1918 { 1919 STUB; 1920 return FALSE; 1921 } 1922 1923 1924 /* 1925 * @unimplemented 1926 */ 1927 BOOL 1928 WINAPI 1929 RegisterWowExec ( 1930 DWORD Unknown0 1931 ) 1932 { 1933 STUB; 1934 return FALSE; 1935 } 1936 1937 1938 /* 1939 * @implemented 1940 */ 1941 BOOL 1942 WINAPI 1943 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs) 1944 { 1945 BASE_API_MESSAGE ApiMessage; 1946 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest; 1947 PCSR_CAPTURE_BUFFER CaptureBuffer; 1948 1949 /* Allocate the capture buffer */ 1950 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs); 1951 if (CaptureBuffer == NULL) 1952 { 1953 BaseSetLastNTError(STATUS_NO_MEMORY); 1954 return FALSE; 1955 } 1956 1957 /* Setup the input parameters */ 1958 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs; 1959 CsrCaptureMessageBuffer(CaptureBuffer, 1960 lpszzCurDirs, 1961 cchCurDirs, 1962 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs); 1963 1964 /* Call CSRSS */ 1965 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1966 CaptureBuffer, 1967 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs), 1968 sizeof(*VDMCurrentDirsRequest)); 1969 1970 /* Free the capture buffer */ 1971 CsrFreeCaptureBuffer(CaptureBuffer); 1972 1973 /* Set the last error */ 1974 BaseSetLastNTError(ApiMessage.Status); 1975 1976 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE; 1977 } 1978 1979 /* 1980 * @unimplemented 1981 */ 1982 DWORD 1983 WINAPI 1984 VDMConsoleOperation ( 1985 DWORD Unknown0, 1986 DWORD Unknown1 1987 ) 1988 { 1989 STUB; 1990 return 0; 1991 } 1992 1993 1994 /* 1995 * @unimplemented 1996 */ 1997 BOOL 1998 WINAPI 1999 VDMOperationStarted(IN ULONG Unknown0) 2000 { 2001 DPRINT1("VDMOperationStarted(%d)\n", Unknown0); 2002 2003 return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler, 2004 NULL, 2005 0, 2006 Unknown0); 2007 } 2008