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 EnvironmentSize = 0; 750 SIZE_T RegionSize; 751 PWCHAR Environment, NewEnvironment = NULL; 752 ENV_NAME_TYPE NameType; 753 ULONG NameLength, NumChars, Remaining; 754 PWCHAR SourcePtr, DestPtr, StartPtr; 755 756 /* Make sure we have both strings */ 757 if (!AnsiEnv || !UnicodeEnv) 758 { 759 /* Fail */ 760 SetLastError(ERROR_INVALID_PARAMETER); 761 return FALSE; 762 } 763 764 /* Check if an environment was passed in */ 765 if (!lpEnvironment) 766 { 767 /* Nope, create one */ 768 Status = RtlCreateEnvironment(TRUE, &Environment); 769 if (!NT_SUCCESS(Status)) goto Cleanup; 770 } 771 else 772 { 773 /* Use the one we got */ 774 Environment = lpEnvironment; 775 } 776 777 /* Do we have something now ? */ 778 if (!Environment) 779 { 780 /* Still not, bail out */ 781 SetLastError(ERROR_BAD_ENVIRONMENT); 782 goto Cleanup; 783 } 784 785 /* 786 * Count how much space the whole environment takes. The environment block is 787 * doubly NULL-terminated (NULL from last string and final NULL terminator). 788 */ 789 SourcePtr = Environment; 790 while (!(*SourcePtr++ == UNICODE_NULL && *SourcePtr == UNICODE_NULL)) 791 ++EnvironmentSize; 792 EnvironmentSize += 2; // Add the two terminating NULLs 793 794 /* 795 * Allocate a new copy large enough to hold all the environment with paths 796 * in their short form. Since the short form of a path can be a bit longer 797 * than its long form, for example in the case where characters that are 798 * invalid in the 8.3 representation are present in the long path name: 799 * 'C:\\a+b' --> 'C:\\A_B~1', or: 800 * 'C:\\a b' --> 'C:\\AB2761~1' (with checksum inserted), 801 * we suppose that the possible total number of extra characters needed to 802 * convert the long paths into their short form is at most equal to MAX_PATH. 803 */ 804 RegionSize = (EnvironmentSize + MAX_PATH) * sizeof(WCHAR); 805 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 806 (PVOID*)&NewEnvironment, 807 0, 808 &RegionSize, 809 MEM_COMMIT, 810 PAGE_READWRITE); 811 if (!NT_SUCCESS(Status)) 812 { 813 /* We failed, bail out */ 814 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 815 NewEnvironment = NULL; 816 goto Cleanup; 817 } 818 819 /* Parse the environment block */ 820 Remaining = MAX_PATH - 2; // '-2': remove the last two NULLs. FIXME: is it really needed?? 821 SourcePtr = Environment; 822 DestPtr = NewEnvironment; 823 824 /* Loop through all the environment strings */ 825 while (*SourcePtr != UNICODE_NULL) 826 { 827 /* 828 * 1. Check the type of the environment variable and copy its name. 829 */ 830 831 /* Regular environment variable */ 832 if (*SourcePtr != L'=') 833 { 834 StartPtr = SourcePtr; 835 836 /* Copy the environment variable name, including the '=' */ 837 while (*SourcePtr != UNICODE_NULL) 838 { 839 *DestPtr++ = *SourcePtr; 840 if (*SourcePtr++ == L'=') break; 841 } 842 843 /* Guess the type of the environment variable */ 844 NameType = BaseGetEnvNameType_U(StartPtr, SourcePtr - StartPtr - 1); 845 } 846 /* 'Current directory' environment variable (i.e. of '=X:=' form) */ 847 else // if (*SourcePtr == L'=') 848 { 849 /* First assume we have a possibly malformed environment variable */ 850 NameType = EnvNameNotAPath; 851 852 /* Check for a valid 'Current directory' environment variable */ 853 if (IS_ALPHA(SourcePtr[1]) && SourcePtr[2] == L':' && SourcePtr[3] == L'=') 854 { 855 /* 856 * Small optimization: convert the path to short form only if 857 * the current directory is not the root directory (i.e. not 858 * of the '=X:=Y:\' form), otherwise just do a simple copy. 859 */ 860 if ( wcslen(SourcePtr) >= ARRAYSIZE("=X:=Y:\\")-1 && 861 !( IS_ALPHA(SourcePtr[4]) && SourcePtr[5] == L':' && 862 IS_PATH_SEPARATOR(SourcePtr[6]) && SourcePtr[7] == UNICODE_NULL ) ) 863 { 864 NameType = EnvNameSinglePath; 865 866 /* Copy the '=X:=' prefix */ 867 *DestPtr++ = SourcePtr[0]; 868 *DestPtr++ = SourcePtr[1]; 869 *DestPtr++ = SourcePtr[2]; 870 *DestPtr++ = SourcePtr[3]; 871 SourcePtr += 4; 872 } 873 } 874 else 875 { 876 /* 877 * Invalid stuff starting with '=', i.e.: 878 * =? (with '?' not being a letter) 879 * =X??? (with '?' not being ":=" and not followed by something longer than 3 characters) 880 * =X:=??? (with '?' not being "X:\\") 881 * 882 * 'NameType' is already set to 'EnvNameNotAPath'. 883 */ 884 } 885 } 886 887 888 /* 889 * 2. Copy the environment value and perform conversions accordingly. 890 */ 891 892 if (NameType == EnvNameNotAPath) 893 { 894 /* Copy everything, including the NULL terminator */ 895 do 896 { 897 *DestPtr++ = *SourcePtr; 898 } while (*SourcePtr++ != UNICODE_NULL); 899 } 900 else if (NameType == EnvNameSinglePath) 901 { 902 /* Convert the path to its short form */ 903 NameLength = wcslen(SourcePtr); 904 NumChars = GetShortPathNameW(SourcePtr, DestPtr, NameLength + 1 + Remaining); 905 if (NumChars == 0 || NumChars > NameLength + Remaining) 906 { 907 /* If the conversion failed, just copy the original value */ 908 RtlCopyMemory(DestPtr, SourcePtr, NameLength * sizeof(WCHAR)); 909 NumChars = NameLength; 910 } 911 DestPtr += NumChars; 912 if (NumChars > NameLength) 913 Remaining -= (NumChars - NameLength); 914 915 SourcePtr += NameLength; 916 917 /* Copy the NULL terminator */ 918 *DestPtr++ = *SourcePtr++; 919 } 920 else // if (NameType == EnvNameMultiplePath) 921 { 922 WCHAR Delimiter; 923 924 /* Loop through the list of paths (delimited by ';') and convert each path to its short form */ 925 do 926 { 927 /* Copy any trailing ';' before going to the next path */ 928 while (*SourcePtr == L';') 929 { 930 *DestPtr++ = *SourcePtr++; 931 } 932 933 StartPtr = SourcePtr; 934 935 /* Find the next path list delimiter or the NULL terminator */ 936 while (*SourcePtr != UNICODE_NULL && *SourcePtr != L';') 937 { 938 ++SourcePtr; 939 } 940 Delimiter = *SourcePtr; 941 942 NameLength = SourcePtr - StartPtr; 943 if (NameLength) 944 { 945 /* 946 * Temporarily replace the possible path list delimiter by NULL. 947 * 'lpEnvironment' must point to a read+write memory buffer! 948 */ 949 *SourcePtr = UNICODE_NULL; 950 951 NumChars = GetShortPathNameW(StartPtr, DestPtr, NameLength + 1 + Remaining); 952 if ( NumChars == 0 || 953 (Delimiter == L';' ? NumChars > NameLength + Remaining 954 : NumChars > NameLength /* + Remaining ?? */) ) 955 { 956 /* If the conversion failed, just copy the original value */ 957 RtlCopyMemory(DestPtr, StartPtr, NameLength * sizeof(WCHAR)); 958 NumChars = NameLength; 959 } 960 DestPtr += NumChars; 961 if (NumChars > NameLength) 962 Remaining -= (NumChars - NameLength); 963 964 /* If removed, restore the path list delimiter in the source environment value and copy it */ 965 if (Delimiter != UNICODE_NULL) 966 { 967 *SourcePtr = Delimiter; 968 *DestPtr++ = *SourcePtr++; 969 } 970 } 971 } while (*SourcePtr != UNICODE_NULL); 972 973 /* Copy the NULL terminator */ 974 *DestPtr++ = *SourcePtr++; 975 } 976 } 977 978 /* NULL-terminate the environment block */ 979 *DestPtr++ = UNICODE_NULL; 980 981 /* Initialize the Unicode string to hold it */ 982 RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, 983 (DestPtr - NewEnvironment) * sizeof(WCHAR)); 984 UnicodeEnv->Length = UnicodeEnv->MaximumLength; 985 986 /* Create its ANSI version */ 987 Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE); 988 if (!NT_SUCCESS(Status)) 989 { 990 /* Set last error if conversion failure */ 991 BaseSetLastNTError(Status); 992 } 993 else 994 { 995 /* Everything went okay, so return success */ 996 Success = TRUE; 997 NewEnvironment = NULL; 998 } 999 1000 Cleanup: 1001 /* Cleanup path starts here, start by destroying the environment copy */ 1002 if (!lpEnvironment && Environment) RtlDestroyEnvironment(Environment); 1003 1004 /* See if we are here due to failure */ 1005 if (NewEnvironment) 1006 { 1007 /* Initialize the paths to be empty */ 1008 RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0); 1009 RtlInitEmptyAnsiString(AnsiEnv, NULL, 0); 1010 1011 /* Free the environment copy */ 1012 RegionSize = 0; 1013 Status = NtFreeVirtualMemory(NtCurrentProcess(), 1014 (PVOID*)&NewEnvironment, 1015 &RegionSize, 1016 MEM_RELEASE); 1017 ASSERT(NT_SUCCESS(Status)); 1018 } 1019 1020 /* Return the result */ 1021 return Success; 1022 } 1023 1024 BOOL 1025 NTAPI 1026 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv, 1027 IN PUNICODE_STRING UnicodeEnv) 1028 { 1029 SIZE_T Dummy = 0; 1030 1031 /* Clear the ANSI buffer since Rtl creates this for us */ 1032 if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv); 1033 1034 /* The Unicode buffer is build by hand, though */ 1035 if (UnicodeEnv->Buffer) 1036 { 1037 /* So clear it through the API */ 1038 NtFreeVirtualMemory(NtCurrentProcess(), 1039 (PVOID*)&UnicodeEnv->Buffer, 1040 &Dummy, 1041 MEM_RELEASE); 1042 } 1043 1044 /* All done */ 1045 return TRUE; 1046 } 1047 1048 1049 /* Check whether a file is an OS/2 or a very old Windows executable 1050 * by testing on import of KERNEL. 1051 * 1052 * FIXME: is reading the module imports the only way of discerning 1053 * old Windows binaries from OS/2 ones ? At least it seems so... 1054 */ 1055 static DWORD WINAPI 1056 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne) 1057 { 1058 DWORD CurPos; 1059 LPWORD modtab = NULL; 1060 LPSTR nametab = NULL; 1061 DWORD Read, Ret; 1062 int i; 1063 1064 Ret = BINARY_OS216; 1065 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); 1066 1067 /* read modref table */ 1068 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1069 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) || 1070 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) || 1071 (Read != (DWORD)ne->ne_cmod * sizeof(WORD))) 1072 { 1073 goto broken; 1074 } 1075 1076 /* read imported names table */ 1077 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1078 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) || 1079 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) || 1080 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab)) 1081 { 1082 goto broken; 1083 } 1084 1085 for(i = 0; i < ne->ne_cmod; i++) 1086 { 1087 LPSTR module; 1088 module = &nametab[modtab[i]]; 1089 if(!strncmp(&module[1], "KERNEL", module[0])) 1090 { 1091 /* very old windows file */ 1092 Ret = BINARY_WIN16; 1093 goto done; 1094 } 1095 } 1096 1097 broken: 1098 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n"); 1099 1100 done: 1101 HeapFree(GetProcessHeap(), 0, modtab); 1102 HeapFree(GetProcessHeap(), 0, nametab); 1103 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN); 1104 return Ret; 1105 } 1106 1107 static DWORD WINAPI 1108 InternalGetBinaryType(HANDLE hFile) 1109 { 1110 union 1111 { 1112 struct 1113 { 1114 unsigned char magic[4]; 1115 unsigned char ignored[12]; 1116 unsigned short type; 1117 } elf; 1118 struct 1119 { 1120 unsigned long magic; 1121 unsigned long cputype; 1122 unsigned long cpusubtype; 1123 unsigned long filetype; 1124 } macho; 1125 IMAGE_DOS_HEADER mz; 1126 } Header; 1127 char magic[4]; 1128 DWORD Read; 1129 1130 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1131 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) || 1132 (Read != sizeof(Header)))) 1133 { 1134 return BINARY_UNKNOWN; 1135 } 1136 1137 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic))) 1138 { 1139 /* FIXME: we don't bother to check byte order, architecture, etc. */ 1140 switch(Header.elf.type) 1141 { 1142 case 2: 1143 return BINARY_UNIX_EXE; 1144 case 3: 1145 return BINARY_UNIX_LIB; 1146 } 1147 return BINARY_UNKNOWN; 1148 } 1149 1150 /* Mach-o File with Endian set to Big Endian or Little Endian*/ 1151 if(Header.macho.magic == 0xFEEDFACE || 1152 Header.macho.magic == 0xCEFAEDFE) 1153 { 1154 switch(Header.macho.filetype) 1155 { 1156 case 0x8: 1157 /* MH_BUNDLE */ 1158 return BINARY_UNIX_LIB; 1159 } 1160 return BINARY_UNKNOWN; 1161 } 1162 1163 /* Not ELF, try DOS */ 1164 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE) 1165 { 1166 /* We do have a DOS image so we will now try to seek into 1167 * the file by the amount indicated by the field 1168 * "Offset to extended header" and read in the 1169 * "magic" field information at that location. 1170 * This will tell us if there is more header information 1171 * to read or not. 1172 */ 1173 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) || 1174 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) || 1175 (Read != sizeof(magic)))) 1176 { 1177 return BINARY_DOS; 1178 } 1179 1180 /* Reading the magic field succeeded so 1181 * we will try to determine what type it is. 1182 */ 1183 if(!memcmp(magic, "PE\0\0", sizeof(magic))) 1184 { 1185 IMAGE_FILE_HEADER FileHeader; 1186 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) || 1187 (Read != sizeof(IMAGE_FILE_HEADER))) 1188 { 1189 return BINARY_DOS; 1190 } 1191 1192 /* FIXME - detect 32/64 bit */ 1193 1194 if(FileHeader.Characteristics & IMAGE_FILE_DLL) 1195 return BINARY_PE_DLL32; 1196 return BINARY_PE_EXE32; 1197 } 1198 1199 if(!memcmp(magic, "NE", 2)) 1200 { 1201 /* This is a Windows executable (NE) header. This can 1202 * mean either a 16-bit OS/2 or a 16-bit Windows or even a 1203 * DOS program (running under a DOS extender). To decide 1204 * which, we'll have to read the NE header. 1205 */ 1206 IMAGE_OS2_HEADER ne; 1207 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) || 1208 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) || 1209 (Read != sizeof(IMAGE_OS2_HEADER))) 1210 { 1211 /* Couldn't read header, so abort. */ 1212 return BINARY_DOS; 1213 } 1214 1215 switch(ne.ne_exetyp) 1216 { 1217 case 2: 1218 return BINARY_WIN16; 1219 case 5: 1220 return BINARY_DOS; 1221 default: 1222 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne); 1223 } 1224 } 1225 return BINARY_DOS; 1226 } 1227 return BINARY_UNKNOWN; 1228 } 1229 1230 /* 1231 * @implemented 1232 */ 1233 BOOL 1234 WINAPI 1235 GetBinaryTypeW ( 1236 LPCWSTR lpApplicationName, 1237 LPDWORD lpBinaryType 1238 ) 1239 { 1240 HANDLE hFile; 1241 DWORD BinType; 1242 1243 if(!lpApplicationName || !lpBinaryType) 1244 { 1245 SetLastError(ERROR_INVALID_PARAMETER); 1246 return FALSE; 1247 } 1248 1249 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL, 1250 OPEN_EXISTING, 0, 0); 1251 if(hFile == INVALID_HANDLE_VALUE) 1252 { 1253 return FALSE; 1254 } 1255 1256 BinType = InternalGetBinaryType(hFile); 1257 CloseHandle(hFile); 1258 1259 switch(BinType) 1260 { 1261 case BINARY_UNKNOWN: 1262 { 1263 WCHAR *dot; 1264 1265 /* 1266 * guess from filename 1267 */ 1268 if(!(dot = wcsrchr(lpApplicationName, L'.'))) 1269 { 1270 return FALSE; 1271 } 1272 if(!lstrcmpiW(dot, L".COM")) 1273 { 1274 *lpBinaryType = SCS_DOS_BINARY; 1275 return TRUE; 1276 } 1277 if(!lstrcmpiW(dot, L".PIF")) 1278 { 1279 *lpBinaryType = SCS_PIF_BINARY; 1280 return TRUE; 1281 } 1282 return FALSE; 1283 } 1284 case BINARY_PE_EXE32: 1285 case BINARY_PE_DLL32: 1286 { 1287 *lpBinaryType = SCS_32BIT_BINARY; 1288 return TRUE; 1289 } 1290 case BINARY_PE_EXE64: 1291 case BINARY_PE_DLL64: 1292 { 1293 *lpBinaryType = SCS_64BIT_BINARY; 1294 return TRUE; 1295 } 1296 case BINARY_WIN16: 1297 { 1298 *lpBinaryType = SCS_WOW_BINARY; 1299 return TRUE; 1300 } 1301 case BINARY_OS216: 1302 { 1303 *lpBinaryType = SCS_OS216_BINARY; 1304 return TRUE; 1305 } 1306 case BINARY_DOS: 1307 { 1308 *lpBinaryType = SCS_DOS_BINARY; 1309 return TRUE; 1310 } 1311 case BINARY_UNIX_EXE: 1312 case BINARY_UNIX_LIB: 1313 { 1314 return FALSE; 1315 } 1316 } 1317 1318 DPRINT1("Invalid binary type %lu returned!\n", BinType); 1319 return FALSE; 1320 } 1321 1322 /* 1323 * @implemented 1324 */ 1325 BOOL 1326 WINAPI 1327 GetBinaryTypeA(IN LPCSTR lpApplicationName, 1328 OUT LPDWORD lpBinaryType) 1329 { 1330 ANSI_STRING ApplicationNameString; 1331 UNICODE_STRING ApplicationNameW; 1332 BOOL StringAllocated = FALSE, Result; 1333 NTSTATUS Status; 1334 1335 RtlInitAnsiString(&ApplicationNameString, lpApplicationName); 1336 1337 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength) 1338 { 1339 StringAllocated = TRUE; 1340 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE); 1341 } 1342 else 1343 { 1344 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE); 1345 } 1346 1347 if (!NT_SUCCESS(Status)) 1348 { 1349 BaseSetLastNTError(Status); 1350 return FALSE; 1351 } 1352 1353 if (StringAllocated) 1354 { 1355 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType); 1356 RtlFreeUnicodeString(&ApplicationNameW); 1357 } 1358 else 1359 { 1360 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType); 1361 } 1362 1363 return Result; 1364 } 1365 1366 /* 1367 * @unimplemented 1368 */ 1369 BOOL 1370 WINAPI 1371 CmdBatNotification ( 1372 DWORD Unknown 1373 ) 1374 { 1375 STUB; 1376 return FALSE; 1377 } 1378 1379 /* 1380 * @implemented 1381 */ 1382 VOID 1383 WINAPI 1384 ExitVDM(BOOL IsWow, ULONG iWowTask) 1385 { 1386 BASE_API_MESSAGE ApiMessage; 1387 PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest; 1388 1389 /* Setup the input parameters */ 1390 ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1391 ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */ 1392 ExitVdm->WaitObjectForVDM = NULL; 1393 1394 /* Call CSRSS */ 1395 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1396 NULL, 1397 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM), 1398 sizeof(*ExitVdm)); 1399 1400 /* Close the returned wait object handle, if any */ 1401 if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL)) 1402 { 1403 CloseHandle(ExitVdm->WaitObjectForVDM); 1404 } 1405 } 1406 1407 /* 1408 * @implemented 1409 */ 1410 BOOL 1411 WINAPI 1412 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData) 1413 { 1414 BOOL Success = FALSE; 1415 NTSTATUS Status; 1416 BASE_API_MESSAGE ApiMessage; 1417 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest; 1418 PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest; 1419 PBASE_SET_REENTER_COUNT SetReenterCount = &ApiMessage.Data.SetReenterCountRequest; 1420 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; 1421 ULONG NumStrings = 0; 1422 1423 /* 1424 * Special case to test whether the VDM is the first one. 1425 */ 1426 if (CommandData == NULL) 1427 { 1428 /* Call CSRSS */ 1429 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1430 NULL, 1431 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM), 1432 sizeof(*IsFirstVdm)); 1433 if (!NT_SUCCESS(ApiMessage.Status)) 1434 { 1435 BaseSetLastNTError(ApiMessage.Status); 1436 return FALSE; 1437 } 1438 1439 /* Return TRUE if this is the first VDM */ 1440 return IsFirstVdm->FirstVDM; 1441 } 1442 1443 /* CommandData != NULL */ 1444 1445 /* 1446 * Special case to increment or decrement the reentrancy count. 1447 */ 1448 if ((CommandData->VDMState == VDM_INC_REENTER_COUNT) || 1449 (CommandData->VDMState == VDM_DEC_REENTER_COUNT)) 1450 { 1451 /* Setup the input parameters */ 1452 SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1453 SetReenterCount->fIncDec = CommandData->VDMState; 1454 1455 /* Call CSRSS */ 1456 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1457 NULL, 1458 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount), 1459 sizeof(*SetReenterCount)); 1460 if (!NT_SUCCESS(ApiMessage.Status)) 1461 { 1462 BaseSetLastNTError(ApiMessage.Status); 1463 return FALSE; 1464 } 1465 1466 return TRUE; 1467 } 1468 1469 /* 1470 * TODO! 1471 * Special case to retrieve or set WOW information. 1472 */ 1473 // TODO: if CommandData->VDMState & (VDM_LIST_WOW_PROCESSES | VDM_LIST_WOW_TASKS | VDM_ADD_WOW_TASK) 1474 // then call BasepGetNextVDMCommand in a simpler way! 1475 1476 /* 1477 * Regular case. 1478 */ 1479 1480 /* Clear the structure */ 1481 RtlZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand)); 1482 1483 /* Setup the input parameters */ 1484 GetNextVdmCommand->iTask = CommandData->TaskId; 1485 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1486 GetNextVdmCommand->CmdLen = CommandData->CmdLen; 1487 GetNextVdmCommand->AppLen = CommandData->AppLen; 1488 GetNextVdmCommand->PifLen = CommandData->PifLen; 1489 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen; 1490 GetNextVdmCommand->EnvLen = CommandData->EnvLen; 1491 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen; 1492 GetNextVdmCommand->TitleLen = CommandData->TitleLen; 1493 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen; 1494 GetNextVdmCommand->VDMState = CommandData->VDMState; 1495 1496 /* Count the number of strings */ 1497 if (CommandData->CmdLen) NumStrings++; 1498 if (CommandData->AppLen) NumStrings++; 1499 if (CommandData->PifLen) NumStrings++; 1500 if (CommandData->CurDirectoryLen) NumStrings++; 1501 if (CommandData->EnvLen) NumStrings++; 1502 if (CommandData->DesktopLen) NumStrings++; 1503 if (CommandData->TitleLen) NumStrings++; 1504 if (CommandData->ReservedLen) NumStrings++; 1505 1506 /* Allocate the capture buffer */ 1507 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1, 1508 GetNextVdmCommand->CmdLen 1509 + GetNextVdmCommand->AppLen 1510 + GetNextVdmCommand->PifLen 1511 + GetNextVdmCommand->CurDirectoryLen 1512 + GetNextVdmCommand->EnvLen 1513 + GetNextVdmCommand->DesktopLen 1514 + GetNextVdmCommand->TitleLen 1515 + GetNextVdmCommand->ReservedLen 1516 + sizeof(*GetNextVdmCommand->StartupInfo)); 1517 if (CaptureBuffer == NULL) 1518 { 1519 BaseSetLastNTError(STATUS_NO_MEMORY); 1520 goto Cleanup; 1521 } 1522 1523 /* Capture the data */ 1524 1525 CsrAllocateMessagePointer(CaptureBuffer, 1526 sizeof(*GetNextVdmCommand->StartupInfo), 1527 (PVOID*)&GetNextVdmCommand->StartupInfo); 1528 1529 if (CommandData->CmdLen) 1530 { 1531 CsrAllocateMessagePointer(CaptureBuffer, 1532 CommandData->CmdLen, 1533 (PVOID*)&GetNextVdmCommand->CmdLine); 1534 } 1535 1536 if (CommandData->AppLen) 1537 { 1538 CsrAllocateMessagePointer(CaptureBuffer, 1539 CommandData->AppLen, 1540 (PVOID*)&GetNextVdmCommand->AppName); 1541 } 1542 1543 if (CommandData->PifLen) 1544 { 1545 CsrAllocateMessagePointer(CaptureBuffer, 1546 CommandData->PifLen, 1547 (PVOID*)&GetNextVdmCommand->PifFile); 1548 } 1549 1550 if (CommandData->CurDirectoryLen) 1551 { 1552 CsrAllocateMessagePointer(CaptureBuffer, 1553 CommandData->CurDirectoryLen, 1554 (PVOID*)&GetNextVdmCommand->CurDirectory); 1555 } 1556 1557 if (CommandData->EnvLen) 1558 { 1559 CsrAllocateMessagePointer(CaptureBuffer, 1560 CommandData->EnvLen, 1561 (PVOID*)&GetNextVdmCommand->Env); 1562 } 1563 1564 if (CommandData->DesktopLen) 1565 { 1566 CsrAllocateMessagePointer(CaptureBuffer, 1567 CommandData->DesktopLen, 1568 (PVOID*)&GetNextVdmCommand->Desktop); 1569 } 1570 1571 if (CommandData->TitleLen) 1572 { 1573 CsrAllocateMessagePointer(CaptureBuffer, 1574 CommandData->TitleLen, 1575 (PVOID*)&GetNextVdmCommand->Title); 1576 } 1577 1578 if (CommandData->ReservedLen) 1579 { 1580 CsrAllocateMessagePointer(CaptureBuffer, 1581 CommandData->ReservedLen, 1582 (PVOID*)&GetNextVdmCommand->Reserved); 1583 } 1584 1585 while (TRUE) 1586 { 1587 /* Call CSRSS */ 1588 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1589 CaptureBuffer, 1590 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand), 1591 sizeof(*GetNextVdmCommand)); 1592 1593 /* Exit the waiting loop if we did not receive any event handle */ 1594 if (GetNextVdmCommand->WaitObjectForVDM == NULL) 1595 break; 1596 1597 /* Wait for the event to become signaled and try again */ 1598 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM, 1599 FALSE, NULL); 1600 if (Status != STATUS_SUCCESS) 1601 { 1602 /* Fail if we timed out, or if some other error happened */ 1603 BaseSetLastNTError(Status); 1604 goto Cleanup; 1605 } 1606 1607 /* Set the retry flag, clear the exit code, and retry a query */ 1608 GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY; 1609 GetNextVdmCommand->ExitCode = 0; 1610 } 1611 1612 if (!NT_SUCCESS(Status)) 1613 { 1614 if (Status == STATUS_INVALID_PARAMETER) 1615 { 1616 /* 1617 * One of the buffer lengths was less than required. Store the correct ones. 1618 * Note that the status code is not STATUS_BUFFER_TOO_SMALL as one would expect, 1619 * in order to keep compatibility with Windows 2003 BASESRV.DLL. 1620 */ 1621 CommandData->CmdLen = GetNextVdmCommand->CmdLen; 1622 CommandData->AppLen = GetNextVdmCommand->AppLen; 1623 CommandData->PifLen = GetNextVdmCommand->PifLen; 1624 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen; 1625 CommandData->EnvLen = GetNextVdmCommand->EnvLen; 1626 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen; 1627 CommandData->TitleLen = GetNextVdmCommand->TitleLen; 1628 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen; 1629 } 1630 else 1631 { 1632 /* Any other failure */ 1633 CommandData->CmdLen = 0; 1634 CommandData->AppLen = 0; 1635 CommandData->PifLen = 0; 1636 CommandData->CurDirectoryLen = 0; 1637 CommandData->EnvLen = 0; 1638 CommandData->DesktopLen = 0; 1639 CommandData->TitleLen = 0; 1640 CommandData->ReservedLen = 0; 1641 } 1642 1643 BaseSetLastNTError(Status); 1644 goto Cleanup; 1645 } 1646 1647 /* Write back the standard handles */ 1648 CommandData->StdIn = GetNextVdmCommand->StdIn; 1649 CommandData->StdOut = GetNextVdmCommand->StdOut; 1650 CommandData->StdErr = GetNextVdmCommand->StdErr; 1651 1652 /* Write back the startup info */ 1653 RtlMoveMemory(&CommandData->StartupInfo, 1654 GetNextVdmCommand->StartupInfo, 1655 sizeof(*GetNextVdmCommand->StartupInfo)); 1656 1657 if (CommandData->CmdLen) 1658 { 1659 /* Write back the command line */ 1660 RtlMoveMemory(CommandData->CmdLine, 1661 GetNextVdmCommand->CmdLine, 1662 GetNextVdmCommand->CmdLen); 1663 1664 /* Set the actual length */ 1665 CommandData->CmdLen = GetNextVdmCommand->CmdLen; 1666 } 1667 1668 if (CommandData->AppLen) 1669 { 1670 /* Write back the application name */ 1671 RtlMoveMemory(CommandData->AppName, 1672 GetNextVdmCommand->AppName, 1673 GetNextVdmCommand->AppLen); 1674 1675 /* Set the actual length */ 1676 CommandData->AppLen = GetNextVdmCommand->AppLen; 1677 } 1678 1679 if (CommandData->PifLen) 1680 { 1681 /* Write back the PIF file name */ 1682 RtlMoveMemory(CommandData->PifFile, 1683 GetNextVdmCommand->PifFile, 1684 GetNextVdmCommand->PifLen); 1685 1686 /* Set the actual length */ 1687 CommandData->PifLen = GetNextVdmCommand->PifLen; 1688 } 1689 1690 if (CommandData->CurDirectoryLen) 1691 { 1692 /* Write back the current directory */ 1693 RtlMoveMemory(CommandData->CurDirectory, 1694 GetNextVdmCommand->CurDirectory, 1695 GetNextVdmCommand->CurDirectoryLen); 1696 1697 /* Set the actual length */ 1698 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen; 1699 } 1700 1701 if (CommandData->EnvLen) 1702 { 1703 /* Write back the environment */ 1704 RtlMoveMemory(CommandData->Env, 1705 GetNextVdmCommand->Env, 1706 GetNextVdmCommand->EnvLen); 1707 1708 /* Set the actual length */ 1709 CommandData->EnvLen = GetNextVdmCommand->EnvLen; 1710 } 1711 1712 if (CommandData->DesktopLen) 1713 { 1714 /* Write back the desktop name */ 1715 RtlMoveMemory(CommandData->Desktop, 1716 GetNextVdmCommand->Desktop, 1717 GetNextVdmCommand->DesktopLen); 1718 1719 /* Set the actual length */ 1720 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen; 1721 } 1722 1723 if (CommandData->TitleLen) 1724 { 1725 /* Write back the title */ 1726 RtlMoveMemory(CommandData->Title, 1727 GetNextVdmCommand->Title, 1728 GetNextVdmCommand->TitleLen); 1729 1730 /* Set the actual length */ 1731 CommandData->TitleLen = GetNextVdmCommand->TitleLen; 1732 } 1733 1734 if (CommandData->ReservedLen) 1735 { 1736 /* Write back the reserved parameter */ 1737 RtlMoveMemory(CommandData->Reserved, 1738 GetNextVdmCommand->Reserved, 1739 GetNextVdmCommand->ReservedLen); 1740 1741 /* Set the actual length */ 1742 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen; 1743 } 1744 1745 /* Write the remaining output parameters */ 1746 CommandData->TaskId = GetNextVdmCommand->iTask; 1747 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags; 1748 CommandData->CodePage = GetNextVdmCommand->CodePage; 1749 CommandData->ExitCode = GetNextVdmCommand->ExitCode; 1750 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive; 1751 CommandData->VDMState = GetNextVdmCommand->VDMState; 1752 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat; 1753 1754 /* It was successful */ 1755 Success = TRUE; 1756 1757 Cleanup: 1758 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer); 1759 return Success; 1760 } 1761 1762 1763 /* 1764 * @implemented 1765 */ 1766 DWORD 1767 WINAPI 1768 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs) 1769 { 1770 BASE_API_MESSAGE ApiMessage; 1771 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest; 1772 PCSR_CAPTURE_BUFFER CaptureBuffer; 1773 1774 /* Allocate the capture buffer */ 1775 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs); 1776 if (CaptureBuffer == NULL) 1777 { 1778 BaseSetLastNTError(STATUS_NO_MEMORY); 1779 return 0; 1780 } 1781 1782 /* Setup the input parameters */ 1783 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs; 1784 CsrAllocateMessagePointer(CaptureBuffer, 1785 cchCurDirs, 1786 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs); 1787 1788 /* Call CSRSS */ 1789 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1790 CaptureBuffer, 1791 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs), 1792 sizeof(*VDMCurrentDirsRequest)); 1793 1794 /* Set the last error */ 1795 BaseSetLastNTError(ApiMessage.Status); 1796 1797 if (NT_SUCCESS(ApiMessage.Status)) 1798 { 1799 /* Copy the result */ 1800 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs); 1801 } 1802 1803 /* Free the capture buffer */ 1804 CsrFreeCaptureBuffer(CaptureBuffer); 1805 1806 /* Return the size if it was successful, or if the buffer was too small */ 1807 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL)) 1808 ? VDMCurrentDirsRequest->cchCurDirs : 0; 1809 } 1810 1811 1812 /* 1813 * @implemented (undocumented) 1814 */ 1815 BOOL 1816 WINAPI 1817 RegisterConsoleVDM(IN DWORD dwRegisterFlags, 1818 IN HANDLE hStartHardwareEvent, 1819 IN HANDLE hEndHardwareEvent, 1820 IN HANDLE hErrorHardwareEvent, 1821 IN DWORD dwUnusedVar, 1822 OUT LPDWORD lpVideoStateLength, 1823 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER* 1824 IN PVOID lpUnusedBuffer, 1825 IN DWORD dwUnusedBufferLength, 1826 IN COORD dwVDMBufferSize, 1827 OUT PVOID* lpVDMBuffer) 1828 { 1829 BOOL Success; 1830 CONSOLE_API_MESSAGE ApiMessage; 1831 PCONSOLE_REGISTERVDM RegisterVDMRequest = &ApiMessage.Data.RegisterVDMRequest; 1832 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; 1833 1834 /* Set up the data to send to the Console Server */ 1835 RegisterVDMRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; 1836 RegisterVDMRequest->RegisterFlags = dwRegisterFlags; 1837 1838 if (dwRegisterFlags != 0) 1839 { 1840 RegisterVDMRequest->StartHardwareEvent = hStartHardwareEvent; 1841 RegisterVDMRequest->EndHardwareEvent = hEndHardwareEvent; 1842 RegisterVDMRequest->ErrorHardwareEvent = hErrorHardwareEvent; 1843 1844 RegisterVDMRequest->VDMBufferSize = dwVDMBufferSize; 1845 1846 #if 0 1847 RegisterVDMRequest->UnusedBufferLength = dwUnusedBufferLength; 1848 1849 /* Allocate a Capture Buffer */ 1850 CaptureBuffer = CsrAllocateCaptureBuffer(1, dwUnusedBufferLength); 1851 if (CaptureBuffer == NULL) 1852 { 1853 DPRINT1("CsrAllocateCaptureBuffer failed!\n"); 1854 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1855 return FALSE; 1856 } 1857 1858 /* Capture the buffer to write */ 1859 CsrCaptureMessageBuffer(CaptureBuffer, 1860 (PVOID)lpUnusedBuffer, 1861 dwUnusedBufferLength, 1862 (PVOID*)&RegisterVDMRequest->UnusedBuffer); 1863 #endif 1864 } 1865 else 1866 { 1867 // CaptureBuffer = NULL; 1868 } 1869 1870 /* Call the server */ 1871 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1872 CaptureBuffer, 1873 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepRegisterVDM), 1874 sizeof(*RegisterVDMRequest)); 1875 1876 /* Check for success */ 1877 Success = NT_SUCCESS(ApiMessage.Status); 1878 1879 /* Release the capture buffer if needed */ 1880 if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); 1881 1882 /* Retrieve the results */ 1883 if (Success) 1884 { 1885 if (dwRegisterFlags != 0) 1886 { 1887 _SEH2_TRY 1888 { 1889 *lpVideoStateLength = RegisterVDMRequest->VideoStateLength; 1890 *lpVideoState = RegisterVDMRequest->VideoState; 1891 *lpVDMBuffer = RegisterVDMRequest->VDMBuffer; 1892 } 1893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1894 { 1895 SetLastError(ERROR_INVALID_ACCESS); 1896 Success = FALSE; 1897 } 1898 _SEH2_END; 1899 } 1900 } 1901 else 1902 { 1903 BaseSetLastNTError(ApiMessage.Status); 1904 } 1905 1906 /* Return success status */ 1907 return Success; 1908 } 1909 1910 1911 /* 1912 * @unimplemented 1913 */ 1914 BOOL 1915 WINAPI 1916 RegisterWowBaseHandlers ( 1917 DWORD Unknown0 1918 ) 1919 { 1920 STUB; 1921 return FALSE; 1922 } 1923 1924 1925 /* 1926 * @unimplemented 1927 */ 1928 BOOL 1929 WINAPI 1930 RegisterWowExec ( 1931 DWORD Unknown0 1932 ) 1933 { 1934 STUB; 1935 return FALSE; 1936 } 1937 1938 1939 /* 1940 * @implemented 1941 */ 1942 BOOL 1943 WINAPI 1944 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs) 1945 { 1946 BASE_API_MESSAGE ApiMessage; 1947 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest; 1948 PCSR_CAPTURE_BUFFER CaptureBuffer; 1949 1950 /* Allocate the capture buffer */ 1951 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs); 1952 if (CaptureBuffer == NULL) 1953 { 1954 BaseSetLastNTError(STATUS_NO_MEMORY); 1955 return FALSE; 1956 } 1957 1958 /* Setup the input parameters */ 1959 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs; 1960 CsrCaptureMessageBuffer(CaptureBuffer, 1961 lpszzCurDirs, 1962 cchCurDirs, 1963 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs); 1964 1965 /* Call CSRSS */ 1966 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 1967 CaptureBuffer, 1968 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs), 1969 sizeof(*VDMCurrentDirsRequest)); 1970 1971 /* Free the capture buffer */ 1972 CsrFreeCaptureBuffer(CaptureBuffer); 1973 1974 /* Set the last error */ 1975 BaseSetLastNTError(ApiMessage.Status); 1976 1977 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE; 1978 } 1979 1980 /* 1981 * @unimplemented 1982 */ 1983 DWORD 1984 WINAPI 1985 VDMConsoleOperation ( 1986 DWORD Unknown0, 1987 DWORD Unknown1 1988 ) 1989 { 1990 STUB; 1991 return 0; 1992 } 1993 1994 1995 /* 1996 * @unimplemented 1997 */ 1998 BOOL 1999 WINAPI 2000 VDMOperationStarted(IN ULONG Unknown0) 2001 { 2002 DPRINT1("VDMOperationStarted(%d)\n", Unknown0); 2003 2004 return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler, 2005 NULL, 2006 0, 2007 Unknown0); 2008 } 2009