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